diff --git a/CMake/CheckX11Extensions.cmake b/CMake/CheckX11Extensions.cmake new file mode 100644 index 00000000..a6f9b18b --- /dev/null +++ b/CMake/CheckX11Extensions.cmake @@ -0,0 +1,88 @@ +# - Check if X11 RandR extension is available +# Check if the X11 extension RandR is available. +# This macro defines : +# - X11_RANDR_FOUND, If set to NO RandR is not available. +# - X11_RANDR_INCLUDE_DIR, includes directory containing the RandR header. +# - X11_RANDR_LIBRARIES, libraries to link in the library to use RandR. +# +# Created by Olivier Delannoy. +macro(CHECK_X11_XRANDR) + message(STATUS "Checking for X11 extension XRandR") + set(X11_XRANDR_FOUND "NO") + find_path(X11_XRANDR_INCLUDE_DIR "X11/extensions/Xrandr.h" + PATHS + /usr/local/include + /usr/local/X11/include + /usr/local/X11R6/include + /usr/include + /usr/X11/include + /usr/X11R6/include) + + find_library(X11_XRANDR_LIBRARIES NAMES Xrandr + PATHS + /usr/local/lib + /usr/local/X11/lib + /usr/local/X11R6/lib + /usr/lib + /usr/X11/lib + /usr/X11R6/lib) + # Create check if file compiles with randr + + if (X11_XRANDR_LIBRARIES AND X11_XRANDR_INCLUDE_DIR) + set(X11_XRANDR_FOUND "YES") + endif (X11_XRANDR_LIBRARIES AND X11_XRANDR_INCLUDE_DIR) + + if (X11_XRANDR_FOUND) + message(STATUS "Checking for X11 extension XRandR -- found") + else (X11_XRANDR_FOUND) + message(STATUS "Checking for X11 extension XRandR -- not found") + endif (X11_XRANDR_FOUND) + + mark_as_advanced(X11_XRANDR_LIBRARIES X11_XRANDR_INCLUDE_DIR) +endmacro(CHECK_X11_XRANDR) + + +# - Check if X11 VidMod extension is available +# Check if the X11 extension VidMod is available. +# This macro defines : +# - X11_VIDMOD_FOUND, If set to NO VidMod is not available. +# - X11_VIDMOD_INCLUDE_DIR, includes directory containing the headers. +# - X11_VIDMOD_LIBRARIES, libraries to link in the libraries. +# +# Created by Olivier Delannoy. +macro(CHECK_X11_XF86VIDMODE) + message(STATUS "Checking for X11 extension xf86vidmode") + set(X11_XF86VIDMODE_FOUND "NO") + find_path(X11_XF86VIDMODE_INCLUDE_DIR "X11/extensions/xf86vmode.h" + PATHS + /usr/local/include + /usr/local/X11/include + /usr/local/X11R6/include + /usr/include + /usr/X11/include + /usr/X11R6/include) + + find_library(X11_XF86VIDMODE_LIBRARIES NAMES Xxf86vm PATHS + /usr/local/lib + /usr/local/X11/lib + /usr/local/X11R6/lib + /usr/lib + /usr/X11/lib + /usr/X11R6/lib) + # Add a test case here + if (X11_XF86VIDMODE_LIBRARIES AND X11_XF86VIDMODE_INCLUDE_DIR) + set(X11_XF86VIDMODE_FOUND "YES") + endif (X11_XF86VIDMODE_LIBRARIES AND X11_XF86VIDMODE_INCLUDE_DIR) + + if (X11_XF86VIDMODE_FOUND) + message(STATUS "Checking for X11 extension xf86vidmode -- found") + else (X11_XF86VIDMODE_FOUND) + message(STATUS "Checking for X11 extension xf86vidmode -- not found") + endif(X11_XF86VIDMODE_FOUND) + + mark_as_advanced( + X11_XF86VIDMODE_LIBRARIES + X11_XF86VIDMODE_INCLUDE_DIR + ) + +endmacro(CHECK_X11_XF86VIDMODE) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..7acc5af1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,163 @@ +project(GLFW C) + +set(GLFW_VERSION_MAJOR "2") +set(GLFW_VERSION_MINOR "7") +set(GLFW_VERSION_PATCH "0") +set(GLFW_VERSION_EXTRA "") +set(GLFW_VERSION "${GLFW_VERSION_MAJOR}.${GLFW_VERSION_MINOR}") +set(GLFW_VERSION_FULL + "${GLFW_VERSION}.${GLFW_VERSION_PATCH}${GLFW_VERSION_EXTRA}") + +cmake_minimum_required(VERSION 2.4) + +include(CheckFunctionExists) +include(CheckSymbolExists) + +# Stuff common to all platform +find_package(OpenGL REQUIRED) + +set(common_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/lib/enable.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/fullscreen.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/glext.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/init.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/input.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/joystick.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/time.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/window.c +) + +# Stuff specific to WGL on Win32 +if (WIN32) + message(STATUS "Building GLFW for WGL on a Win32 system") + + # Set up library and include paths + set(CMAKE_REQUIRED_LIBRARIES ${OPENGL_gl_LIBRARY}) + list(APPEND GLFW_INCLUDE_DIR ${OPENGL_INCLUDE_DIR}) + list(APPEND GLFW_LIBRARIES ${OPENGL_gl_LIBRARY}) + + # Select platform specific code + add_subdirectory(lib/win32) +endif (WIN32) + +# Stuff specific to GLX on Unix-like platforms +if (UNIX AND NOT APPLE AND NOT CYGWIN) + message(STATUS "Building GLFW for GLX on a Unix-like system") + + # Set up library and include paths + set(CMAKE_REQUIRED_LIBRARIES ${X11_X11_LIB} ${OPENGL_gl_LIBRARY}) + list(APPEND GLFW_INCLUDE_DIR ${X11_X11_INCLUDE_PATH}) + list(APPEND GLFW_LIBRARIES ${X11_X11_LIB}) + list(APPEND GLFW_INCLUDE_DIR ${OPENGL_INCLUDE_DIR}) + list(APPEND GLFW_LIBRARIES ${OPENGL_gl_LIBRARY}) + + # Detect X11 extension + include(${CMAKE_CURRENT_SOURCE_DIR}/CMake/CheckX11Extensions.cmake) + + # Check for XRandR (modern resolution switching extension) + CHECK_X11_XRANDR() + if (X11_XRANDR_FOUND) + set(_GLFW_HAS_XRANDR 1) + list(APPEND GLFW_INCLUDE_DIR ${X11_XRANDR_INCLUDE_DIR}) + list(APPEND GLFW_LIBRARIES ${X11_XRANDR_LIBRARIES}) + endif(X11_XRANDR_FOUND) + + # Check for xf86vidmode (fallback legacy resolution switching extension) + if (NOT X11_XRANDR_FOUND) + CHECK_X11_XF86VIDMODE() + if (X11_XF86VIDMODE_FOUND) + set(_GLFW_HAS_XF86VIDMODE 1) + list(APPEND GLFW_INCLUDE_DIR ${X11_XF86VIDMODE_INCLUDE_DIR}) + list(APPEND GLFW_LIBRARIES ${X11_XF86VIDMODE_LIBRARIES}) + endif(X11_XF86VIDMODE_FOUND) + endif (NOT X11_XRANDR_FOUND) + + CHECK_FUNCTION_EXISTS(glXGetProcAddress _GLFW_HAS_GLXGETPROCADDRESS) + + if (NOT _GLFW_HAS_GLXGETPROCADDRESS) + CHECK_FUNCTION_EXISTS(glXGetProcAddressARB _GLFW_HAS_GLXGETPROCADDRESSARB) + endif (NOT _GLFW_HAS_GLXGETPROCADDRESS) + + if (NOT _GLFW_HAS_GLXGETPROCADDRESS AND NOT _GLFW_HAS_GLXGETPROCADDRESSARB) + CHECK_FUNCTION_EXISTS(glXGetProcAddressEXT _GLFW_HAS_GLXGETPROCADDRESSEXT) + endif (NOT _GLFW_HAS_GLXGETPROCADDRESS AND NOT _GLFW_HAS_GLXGETPROCADDRESSARB) + + if (NOT _GLFW_HAS_GLXGETPROCADDRESS AND + NOT _GLFW_HAS_GLXGETPROCADDRESSARB AND + NOT _GLFW_HAS_GLXGETPROCADDRESSEXT) + message(WARNING "No glXGetProcAddressXXX variant found") + endif (NOT _GLFW_HAS_GLXGETPROCADDRESS AND + NOT _GLFW_HAS_GLXGETPROCADDRESSARB AND + NOT _GLFW_HAS_GLXGETPROCADDRESSEXT) + + # Select platform specific code + add_subdirectory(lib/x11) +endif(UNIX AND NOT APPLE AND NOT CYGWIN) + +# Stuff specific to AGL and CGL on Mac OS X +if (UNIX AND APPLE) + message(STATUS "Building GLFW for NSOpenGL on Mac OS X") + + # Universal build, decent set of warning flags... + set(CMAKE_OSX_ARCHITECTURES ppc;i386;ppc64;x86_64) + set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk) + set(CMAKE_C_FLAGS "-mmacosx-version-min=10.5 -Wall -Wextra -Wno-unused-parameter -Werror") + + # Set up library and include paths + find_library(COCOA_FRAMEWORK Cocoa) + list(APPEND GLFW_LIBRARIES ${COCOA_FRAMEWORK}) + list(APPEND GLFW_LIBRARIES ${OPENGL_gl_LIBRARY}) + + # Select platform specific code + add_subdirectory(lib/cocoa) +endif(UNIX AND APPLE) + +add_subdirectory(examples) +add_subdirectory(tests) +#add_subdirectory(docs/doxygen) +#add_subdirectory(docs/manuals) + + +#-------------------------------------------------------------------- +# -- Install standard files +#-------------------------------------------------------------------- + +# Install the GLFW header file +install(DIRECTORY include/ DESTINATION include + PATTERN ".svn" EXCLUDE + PATTERN "include/*" +) + +# Install documentation +install( + FILES + COPYING.txt + readme.html + DESTINATION + share/doc/glfw-${GLFW_VERSION_FULL}/ +) + +#-------------------------------------------------------------------- +# -- Additional stuff +#-------------------------------------------------------------------- + +#-------------------------------------------------------------------- +# -- Documentation generation +#-------------------------------------------------------------------- +#include("${CMAKE_CURRENT_SOURCE_DIR}/documentation.cmake") +#configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in" +# "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile" +# IMMEDIATE @ONLY) +#add_doxygen_target("${CMAKE_CURRENT_BINARY_DIR}/Doxyfile") +#add_subdirectory(docs) + +#-------------------------------------------------------------------- +# -- Uninstall operation +# ------------------------------------------------------------------- +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) +add_custom_target(uninstall + "${CMAKE_COMMAND}" -P + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") + diff --git a/COPYING.txt b/COPYING.txt new file mode 100644 index 00000000..0a69446d --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,21 @@ +Copyright (c) 2002-2007 Camilla Berglund + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would + be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source + distribution. + diff --git a/cmake_uninstall.cmake.in b/cmake_uninstall.cmake.in new file mode 100644 index 00000000..17376d2e --- /dev/null +++ b/cmake_uninstall.cmake.in @@ -0,0 +1,22 @@ +IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +STRING(REGEX REPLACE "\n" ";" files "${files}") +FOREACH(file ${files}) + MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + IF(EXISTS "$ENV{DESTDIR}${file}") + EXEC_PROGRAM( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + IF(NOT "${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + ENDIF(NOT "${rm_retval}" STREQUAL 0) + ELSE(EXISTS "$ENV{DESTDIR}${file}") + MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + ENDIF(EXISTS "$ENV{DESTDIR}${file}") +ENDFOREACH(file) + diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..6bc7da29 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,57 @@ +########################################################################## +# Makefile for the GLFW documentation. +########################################################################## + +PDFDOCS = glfwrm.pdf glfwug.pdf +DVIDOCS = glfwrm.dvi glfwug.dvi + + +########################################################################## +# Build macros +########################################################################## +default: pdf +pdf: $(PDFDOCS) +dvi: $(DVIDOCS) + + +########################################################################## +# Clean macros +########################################################################## +clean: + rm -f glfwrm.dvi glfwrm.aux glfwrm.log glfwrm.out glfwrm.pdf glfwrm.toc glfwrm.lot + rm -f glfwug.dvi glfwug.aux glfwug.log glfwug.out glfwug.pdf glfwug.toc + +clean-win: + @.\\cleanup.bat + + +########################################################################## +# Rules for building the GLFW Reference Manual +########################################################################## + +glfwrm.pdf: glfwrm.tex glfwrm.toc glfwrm.lot glfwdoc.sty + pdflatex glfwrm.tex + +glfwrm.dvi: glfwrm.tex glfwrm.toc glfwrm.lot glfwdoc.sty + latex glfwrm.tex + +glfwrm.toc: glfwrm.tex glfwdoc.sty + latex glfwrm.tex + +glfwrm.lot: glfwrm.tex glfwdoc.sty + latex glfwrm.tex + + +########################################################################## +# Rules for building the GLFW Users Guide +########################################################################## + +glfwug.pdf: glfwug.tex glfwug.toc glfwdoc.sty + pdflatex glfwug.tex + +glfwug.dvi: glfwug.tex glfwug.toc glfwdoc.sty + latex glfwug.tex + +glfwug.toc: glfwug.tex glfwdoc.sty + latex glfwug.tex + diff --git a/docs/cleanup.bat b/docs/cleanup.bat new file mode 100644 index 00000000..268a27b6 --- /dev/null +++ b/docs/cleanup.bat @@ -0,0 +1,22 @@ +@echo off + +REM ---------------------------------------------------------------------- +REM Windows cleanup batch file for the GLFW documentation. +REM ---------------------------------------------------------------------- + +REM GLFW Reference Manual +if exist glfwrm.dvi del glfwrm.dvi +if exist glfwrm.aux del glfwrm.aux +if exist glfwrm.log del glfwrm.log +if exist glfwrm.out del glfwrm.out +if exist glfwrm.pdf del glfwrm.pdf +if exist glfwrm.toc del glfwrm.toc +if exist glfwrm.lot del glfwrm.lot + +REM GLFW Users Guide +if exist glfwug.dvi del glfwug.dvi +if exist glfwug.aux del glfwug.aux +if exist glfwug.log del glfwug.log +if exist glfwug.out del glfwug.out +if exist glfwug.pdf del glfwug.pdf +if exist glfwug.toc del glfwug.toc diff --git a/docs/glfwdoc.sty b/docs/glfwdoc.sty new file mode 100644 index 00000000..b7e7b97d --- /dev/null +++ b/docs/glfwdoc.sty @@ -0,0 +1,80 @@ +%------------------------------------------------------------------------- +% Common document formatting and macros for GLFW manuals +%------------------------------------------------------------------------- + +% Misc. document info +\date{\today} + +% Packages +\usepackage{fancyhdr} +\usepackage{titling} +\usepackage{lastpage} +\usepackage{listings} +\usepackage{color} +\usepackage[overload]{textcase} +\usepackage{needspace} +\usepackage{times} + +% Logo macros +\newcommand{\OpenGL}[1][0]{\textbf{OpenGL}\texttrademark} +\newcommand{\GLFW}[1][0]{\textbf{GLFW}} + +% Encoding +\usepackage[latin1]{inputenc} +\usepackage[T1]{fontenc} + +% Page formatting +\usepackage[hmargin=2.5cm]{geometry} +\raggedright +\raggedbottom +\sloppy +\usepackage{parskip} + +% Header and footer +\pagestyle{fancy} +%\lhead{\textit{GLFW Reference Manual}} +\lhead{\textit{GLFW \glfwdoctype}} +\chead{API version \glfwapiver} +\rhead{Page \thepage/\pageref{LastPage}} +\lfoot{} +\cfoot{} +\rfoot{} +\renewcommand{\headrulewidth}{0.4pt} +\renewcommand{\footrulewidth}{0.0pt} + +% Titlepage +\newcommand{\glfwmaketitle}{\begin{titlepage}\ \\% + \begin{center}% + \vspace{7.0cm}{\Huge\textbf{GLFW}}\\% + \rule{10.0cm}{0.5pt}\\% + \vspace{0.5cm}{\LARGE\textbf{\glfwdoctype}}\\% + \vspace{0.8cm}{\large\textbf{API version \glfwapiver}}\\% + \textit{\today}\\% + \vspace{1.5cm}\textbf{\textcopyright2002-2007 Camilla Berglund}\\% + \end{center}\end{titlepage}\newpage} + +% Colors +\definecolor{code}{rgb}{0.9,0.9,1.0} +\definecolor{link}{rgb}{0.6,0.0,0.0} +\definecolor{codeA}{rgb}{0.9,1.0,0.9} +\definecolor{codeB}{rgb}{1.0,0.9,0.9} + +% Code listings +\lstset{frame=single,frameround=tttt,backgroundcolor=\color{code},% + language=C,basicstyle={\ttfamily},% + breaklines,breakindent=0pt,postbreak=\space\space\space\space} + + +% A simple hack for keeping lines together +\newenvironment{mysamepage}[1][2]{\begin{samepage}\needspace{#1\baselineskip}}{\end{samepage}} + +% Macros for automating function reference entries +\newenvironment{refparameters}[1][0]{\begin{mysamepage}\textbf{Parameters}\\}{\end{mysamepage}\bigskip} +\newenvironment{refreturn}[1][0]{\begin{mysamepage}\textbf{Return values}\\}{\end{mysamepage}\bigskip} +\newenvironment{refdescription}[1][0]{\begin{mysamepage}\textbf{Description}\\}{\end{mysamepage}\bigskip} +\newenvironment{refnotes}[1][0]{\begin{mysamepage}\textbf{Notes}\\}{\end{mysamepage}\bigskip} + +% hyperref (bookmarks, links etc) - use this package last +\usepackage[colorlinks=true,linkcolor=link,bookmarks=true,bookmarksopen=true,% + pdfhighlight=/N,bookmarksnumbered=true,bookmarksopenlevel=1,% + pdfview=FitH,pdfstartview=FitH]{hyperref} diff --git a/docs/glfwrm.tex b/docs/glfwrm.tex new file mode 100644 index 00000000..72f87934 --- /dev/null +++ b/docs/glfwrm.tex @@ -0,0 +1,2128 @@ +%------------------------------------------------------------------------- +% GLFW Reference Manual +% API Version: 2.7 +%------------------------------------------------------------------------- + +% Document class +\documentclass[a4paper,11pt,oneside]{report} + +% Document title and API version +\newcommand{\glfwdoctype}[1][0]{Reference Manual} +\newcommand{\glfwapiver}[1][0]{2.7} + +% Common document settings and macros +\input{glfwdoc.sty} + +% PDF specific document settings +\hypersetup{pdftitle={GLFW Reference Manual}} +\hypersetup{pdfauthor={Marcus Geelnard}} +\hypersetup{pdfkeywords={GLFW,OpenGL,reference,manual}} + + +%------------------------------------------------------------------------- +% Document body +%------------------------------------------------------------------------- + +\begin{document} + +\pagestyle{plain} + +% Title page +\glfwmaketitle + +% Summary, trademarks and table of contents +\pagenumbering{roman} +\setcounter{page}{1} + +%------------------------------------------------------------------------- +% Summary and Trademarks +%------------------------------------------------------------------------- +\chapter*{Summary} + +This document is primarily a function reference manual for the \GLFW\ API. +For a description of how to use \GLFW\ you should refer to the +\textit{GLFW Users Guide}. +\vspace{10cm} + +\large +Trademarks + +\small +OpenGL and IRIX are registered trademarks of Silicon Graphics, Inc.\linebreak +Microsoft and Windows are registered trademarks of Microsoft Corporation.\linebreak +Mac OS is a registered trademark of Apple Computer, Inc.\linebreak +Linux is a registered trademark of Linus Torvalds.\linebreak +FreeBSD is a registered trademark of Wind River Systems, Inc.\linebreak +Solaris is a trademark of Sun Microsystems, Inc.\linebreak +UNIX is a registered trademark of The Open Group.\linebreak +X Window System is a trademark of The Open Group.\linebreak +POSIX is a trademark of IEEE.\linebreak +Truevision, TARGA and TGA are registered trademarks of Truevision, Inc.\linebreak + +All other trademarks mentioned in this document are the property of their respective owners. +\normalsize + + +%------------------------------------------------------------------------- +% Table of contents +%------------------------------------------------------------------------- +\tableofcontents + +%------------------------------------------------------------------------- +% List of tables +%------------------------------------------------------------------------- +\listoftables +\pagebreak + + +% Document chapters starts here... +\pagenumbering{arabic} +\setcounter{page}{1} + +\pagestyle{fancy} + + +%------------------------------------------------------------------------- +% Introduction +%------------------------------------------------------------------------- +\chapter{Introduction} +\thispagestyle{fancy} + +\GLFW\ is a portable API (Application Program Interface) that handles +operating system specific tasks related to \OpenGL\ programming. While +\OpenGL\ in general is portable, easy to use and often results in tidy and +compact code, the operating system specific mechanisms that are required +to set up and manage an \OpenGL\ window are quite the opposite. \GLFW\ tries +to remedy this by providing the following functionality: + +\begin{itemize} +\item Opening and managing an \OpenGL\ window. +\item Keyboard, mouse and joystick input. +\item A high precision timer. +\item Support for querying and using \OpenGL\ extensions. +\end{itemize} +\vspace{18pt} + +All this functionality is implemented as a set of easy-to-use functions, +which makes it possible to write an \OpenGL\ application framework in just a +few lines of code. The \GLFW\ API is completely operating system and +platform independent, which makes it very simple to port \GLFW\ based \OpenGL\ +applications to a variety of platforms. + +Currently supported platforms are: +\begin{itemize} +\item Microsoft Windows\textsuperscript{\textregistered} 95/98/ME/NT/2000/XP/Vista. +\item Unix\textsuperscript{\textregistered} or Unix­-like systems running the +X Window System\texttrademark, e.g. Linux\textsuperscript{\textregistered}, +IRIX\textsuperscript{\textregistered}, FreeBSD\textsuperscript{\textregistered}, +Solaris\texttrademark, QNX\textsuperscript{\textregistered} and +Mac OS\textsuperscript{\textregistered} X. +\item Mac OS\textsuperscript{\textregistered} X (Carbon)\footnote{Support for joysticks missing at the time of writing.} +\end{itemize} + + + +%------------------------------------------------------------------------- +% GLFW Operation +%------------------------------------------------------------------------- +\chapter{GLFW Operation Overview} +\thispagestyle{fancy} + + +%------------------------------------------------------------------------- +\section{The GLFW Window} +\GLFW\ only supports one opened window at a time. The window can be either +a normal desktop window or a fullscreen window. The latter is completely +undecorated, without window borders, and covers the entire monitor. With +a fullscreen window, it is also possible to select which video mode to use. + +When a window is opened, an \OpenGL\ rendering context is created and +attached to the entire client area of the window. When the window is closed, +the \OpenGL\ rendering context is detached and destroyed. + +Through a window it is possible to receive user input in the form of +keyboard and mouse input. User input is exposed through the \GLFW\ API via +callback functions. There are different callback functions for dealing with +different kinds of user input. Also, \GLFW\ stores most user input as +internal state that can be queried through different \GLFW\ API functions +(for instance it is possible to query the position of the mouse cursor +with the \textbf{glfwGetMousePos} function). + +As for user input, it is possible to receive information about window +state changes, such as window resize or close events, through callback +functions. It is also possible to query different kinds of window +information through different \GLFW\ API functions. + + +%------------------------------------------------------------------------- +\section{The GLFW Event Loop} +The \GLFW\ event loop is an open loop, which means that it is up to the +programmer to design the loop. Events are processed by calling specific +\GLFW\ functions, which in turn query the system for new input and window +events, and reports these events back to the program through callback +functions. + +The programmer decides when to call the event processing functions, and +when to abort the event loop. + +In pseudo language, a typical event loop might look like this: + +\begin{lstlisting} + repeat until window is closed + { + poll events + draw OpenGL graphics + } +\end{lstlisting} + +There are two ways to handle events in \GLFW : + +\begin{itemize} + \item Block the event loop while waiting for new events. + \item Poll for new events, and continue the loop regardless if there are + any new events or not. +\end{itemize} + +The first method is useful for interactive applications that do not +need to refresh the \OpenGL\ display unless the user interacts with the +application through user input. Typical applications are CAD software +and other kinds of editors. + +The second method is useful for applications that need to refresh the +\OpenGL\ display constantly, regardless of user input, such as games, +demos, 3D animations, screen savers and so on. + + +%------------------------------------------------------------------------- +\section{Callback Functions} +Using callback functions can be a good method for receiving up to date +information about window state and user input. When a window has been +opened, it is possible to register custom callback functions that will +be called when certain events occur. + +Callback functions are called from any of the event polling functions +\textbf{glfwPollEvents}, \textbf{glfwWaitEvents} or +\textbf{glfwSwapBuffers}. + +Callback functions should \emph{only} be used to gather information. Since +the callback functions are called from within the internal \GLFW\ event +polling loops, they should not call any \GLFW\ functions that might +result in considerable \GLFW\ state changes, nor stall the event polling +loop for a lengthy period of time. + +In other words, most or all \OpenGL\ rendering should be called from the +main application event loop, not from any of the \GLFW\ callback +functions. Also, the only \GLFW\ functions that may be safely called from +callback functions are the different Get functions (e.g. +\textbf{glfwGetKey}, \textbf{glfwGetTime}, \textbf{glfwGetWindowParam} +etc). + + +%------------------------------------------------------------------------- +% Function Reference +%------------------------------------------------------------------------- +\chapter{Function Reference} +\thispagestyle{fancy} + +%------------------------------------------------------------------------- +\section{GLFW Initialization and Termination} +Before any \GLFW\ functions can be used, \GLFW\ must be initialized to +ensure proper functionality, and before a program terminates, \GLFW\ has to +be terminated in order to free up resources etc. + + +%------------------------------------------------------------------------- +\subsection{glfwInit} + +\textbf{C language syntax} +\begin{lstlisting} +int glfwInit( void ) +\end{lstlisting} + +\begin{refparameters} +none +\end{refparameters} + +\begin{refreturn} +If the function succeeds, GL\_TRUE is returned.\\ +If the function fails, GL\_FALSE is returned. +\end{refreturn} + +\begin{refdescription} +The glfwInit function initializes \GLFW. No other \GLFW\ functions may be +used before this function has been called. +\end{refdescription} + +\begin{refnotes} +This function may take several seconds to complete on some systems, while +on other systems it may take only a fraction of a second to complete. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwTerminate} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwTerminate( void ) +\end{lstlisting} + +\begin{refparameters} +none +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function terminates \GLFW. Among other things it closes the window, +if it is opened. This function must be called before a program exits. +\end{refdescription} + + +%------------------------------------------------------------------------- +\subsection{glfwGetVersion} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwGetVersion( int *major, int *minor, int *rev ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{major}]\ \\ + Pointer to an integer that will hold the major version number. +\item [\textit{minor}]\ \\ + Pointer to an integer that will hold the minor version number. +\item [\textit{rev}]\ \\ + Pointer to an integer that will hold the revision. +\end{description} +\end{refparameters} + +\begin{refreturn} +The function returns the major and minor version numbers and the revision +for the currently linked \GLFW\ library. +\end{refreturn} + +\begin{refdescription} +The function returns the \GLFW\ library version. +\end{refdescription} + + +%------------------------------------------------------------------------- +\pagebreak +\section{Window Handling} +The main functionality of \GLFW\ is to provide a simple interface to +\OpenGL\ window management. \GLFW\ can open one window, which can be +either a normal desktop window or a fullscreen window. + + +%------------------------------------------------------------------------- +\subsection{glfwOpenWindow} + +\textbf{C language syntax} +\begin{lstlisting} +int glfwOpenWindow( int width, int height, int redbits, + int greenbits, int bluebits, int alphabits, int depthbits, + int stencilbits, int mode ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{width}]\ \\ + The width of the window. If \textit{width} is zero, it will be + calculated as ${width=\frac{4}{3}height}$, if \textit{height} is not + zero. If both \textit{width} and \textit{height} are zero, then + \textit{width} will be set to 640. +\item [\textit{height}]\ \\ + The height of the window. If \textit{height} is zero, it will be + calculated as ${height=\frac{3}{4}width}$, if \textit{width} is not + zero. If both \textit{width} and \textit{height} are zero, then + \textit{height} will be set to 480. +\item [\textit{redbits, greenbits, bluebits}]\ \\ + The number of bits to use for each color component of the color buffer + (0 means default color depth). For instance, setting \textit{redbits=5, + greenbits=6, and bluebits=5} will generate a 16-­bit color buffer, if + possible. +\item [\textit{alphabits}]\ \\ + The number of bits to use for the alpha buffer (0 means no alpha + buffer). +\item [\textit{depthbits}]\ \\ + The number of bits to use for the depth buffer (0 means no depth + buffer). +\item [\textit{stencilbits}]\ \\ + The number of bits to use for the stencil buffer (0 means no stencil + buffer). +\item [\textit{mode}]\ \\ + Selects which type of \OpenGL\ window to use. \textit{mode} can be + either GLFW\_WINDOW, which will generate a normal desktop window, or + GLFW\_FULLSCREEN, which will generate a window which covers the entire + screen. When GLFW\_FULLSCREEN is selected, the video mode will be + changed to the resolution that closest matches the \textit{width} and + \textit{height} parameters. +\end{description} +\end{refparameters} + +\begin{refreturn} +If the function succeeds, GL\_TRUE is returned.\\ +If the function fails, GL\_FALSE is returned. +\end{refreturn} + +\begin{refdescription} +The function opens a window that best matches the parameters given to the +function. How well the resulting window matches the desired window depends +mostly on the available hardware and \OpenGL\ drivers. In general, +selecting a fullscreen mode has better chances of generating a close match +than does a normal desktop window, since \GLFW\ can freely select from all +the available video modes. A desktop window is normally restricted to the +video mode of the desktop. +\end{refdescription} + +\begin{refnotes} +For additional control of window properties, see +\textbf{glfwOpenWindowHint}. + +In fullscreen mode the mouse cursor is hidden by default, and any system +screensavers are prohibited from starting. In windowed mode the mouse +cursor is visible, and screensavers are allowed to start. To change the +visibility of the mouse cursor, use \textbf{glfwEnable} or +\textbf{glfwDisable} with the argument GLFW\_MOUSE\_CURSOR. + +In order to determine the actual properties of an opened window, use +\textbf{glfwGetWindowParam} and \textbf{glfwGetWindowSize} (or +\textbf{glfwSetWindowSizeCallback}). +\end{refnotes} + + +%------------------------------------------------------------------------- +\begin{table}[p] +\begin{center} +\begin{tabular}{|l|l|p{7.0cm}|} \hline \raggedright +\textbf{Name} & \textbf{Default} & \textbf{Description} \\ \hline +GLFW\_REFRESH\_RATE & 0 & Vertical monitor refresh rate in Hz (only used for fullscreen windows). Zero means system default.\\ \hline +GLFW\_ACCUM\_RED\_BITS & 0 & Number of bits for the red channel of the accumulator buffer.\\ \hline +GLFW\_ACCUM\_GREEN\_BITS & 0 & Number of bits for the green channel of the accumulator buffer.\\ \hline +GLFW\_ACCUM\_BLUE\_BITS & 0 & Number of bits for the blue channel of the accumulator buffer.\\ \hline +GLFW\_ACCUM\_ALPHA\_BITS & 0 & Number of bits for the alpha channel of the accumulator buffer.\\ \hline +GLFW\_AUX\_BUFFERS & 0 & Number of auxiliary buffers.\\ \hline +GLFW\_STEREO & GL\_FALSE & Specify if stereo rendering should be supported (can be GL\_TRUE or GL\_FALSE).\\ \hline +GLFW\_WINDOW\_NO\_RESIZE & GL\_FALSE & Specify whether the window can be resized (not used for fullscreen windows).\\ \hline +GLFW\_FSAA\_SAMPLES & 0 & Number of samples to use for the multisampling buffer. Zero disables multisampling.\\ \hline +GLFW\_OPENGL\_VERSION\_MAJOR & 0 & Major number of the desired OpenGL version. + The default requests the highest OpenGL version equal to or lower than 2.1.\\ \hline +GLFW\_OPENGL\_VERSION\_MINOR & 0 & Minor number of the desired OpenGL version. + The default requests the highest OpenGL version equal to or lower than 2.1.\\ \hline +GLFW\_OPENGL\_FORWARD\_COMPAT & GL\_FALSE & Specify whether the OpenGL context should be forward compatible (i.e. disallow legacy functionality). + This hint is ignored for OpenGL version 2.1 and below.\\ \hline +\end{tabular} +\end{center} +\caption{Targets for \textbf{glfwOpenWindowHint}} +\label{tab:winhints} +\end{table} + + +%------------------------------------------------------------------------- +\subsection{glfwOpenWindowHint} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwOpenWindowHint( int target, int hint ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{target}]\ \\ + Can be any of the constants in the table \ref{tab:winhints}. +\item [\textit{hint}]\ \\ + An integer giving the value of the corresponding target (see table + \ref{tab:winhints}). +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function sets additional properties for a window that is to be opened. +For a hint to be registered, the function must be called before calling +\textbf{glfwOpenWindow}. When the \textbf{glfwOpenWindow} function is +called, any hints that were registered with the \textbf{glfwOpenWindowHint} +function are used for setting the corresponding window properties, and +then all hints are reset to their default values. +\end{refdescription} + +\begin{refnotes} +In order to determine the actual properties of an opened window, use +\textbf{glfwGetWindowParam} (after the window has been opened). + +GLFW\_STEREO is a hard constraint. If stereo rendering is requested, but +no stereo rendering capable pixel formats / visuals are available, +\textbf{glfwOpenWindow} will fail. + +The GLFW\_REFRESH\_RATE property should be used with caution. Most +systems have default values for monitor refresh rates that are optimal +for the specific system. Specifying the refresh rate can override these +settings, which can result in suboptimal operation. The monitor may be +unable to display the resulting video signal, or in the worst case it may +even be damaged! + +If you want to create a context with OpenGL version 3.0 or above you have to +set the GLFW\_OPENGL\_VERSION\_MAJOR and GLFW\_OPENGL\_VERSION\_MINOR hints +accordingly. If you don't do this, the highest OpenGL version available for a +context is 2.1 or lower. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwCloseWindow} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwCloseWindow( void ) +\end{lstlisting} + +\begin{refparameters} +none +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function closes an opened window and destroys the associated \OpenGL\ +context. +\end{refdescription} + + +%------------------------------------------------------------------------- +\subsection{glfwSetWindowCloseCallback} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwSetWindowCloseCallback( GLFWwindowclosefun cbfun ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{cbfun}]\ \\ + Pointer to a callback function that will be called when a user requests + that the window should be closed, typically by clicking the window close + icon (e.g. the cross in the upper right corner of a window under + Microsoft Windows). The function should have the following C language + prototype: + + \texttt{int GLFWCALL functionname( void );} + + Where \textit{functionname} is the name of the callback function. The + return value of the callback function indicates wether or not the window + close action should continue. If the function returns GL\_TRUE, the + window will be closed. If the function returns GL\_FALSE, the window + will not be closed. + + If \textit{cbfun} is NULL, any previously selected callback function + will be deselected. +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function selects which function to be called upon a window close +event. + +A window has to be opened for this function to have any effect. +\end{refdescription} + +\begin{refnotes} +Window close events are recorded continuously, but only reported when +\textbf{glfwPollEvents}, \textbf{glfwWaitEvents} or +\textbf{glfwSwapBuffers} is called. + +The \OpenGL\ context is still valid when this function is called. + +Note that the window close callback function is not called when +\textbf{glfwCloseWindow} is called, but only when the close request +comes from the window manager. + +Do \emph{not} call \textbf{glfwCloseWindow} from a window close +callback function. Close the window by returning GL\_TRUE from the +function. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwSetWindowTitle} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwSetWindowTitle( const char *title ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{title}]\ \\ + Pointer to a null terminated ISO~8859-1 (8-bit Latin~1) string that + holds the title of the window. +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function changes the title of the opened window. +\end{refdescription} + +\begin{refnotes} +The title property of a window is often used in situations other than for +the window title, such as the title of an application icon when it is in +iconified state. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwSetWindowSize} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwSetWindowSize( int width, int height ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{width}]\ \\ + Width of the window. +\item [\textit{height}]\ \\ + Height of the window. +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function changes the size of an opened window. The \textit{width} and +\textit{height} parameters denote the size of the client area of the +window (i.e. excluding any window borders and decorations). + +If the window is in fullscreen mode, the video mode will be changed to a +resolution that closest matches the width and height parameters (the +number of color bits will not be changed). +\end{refdescription} + +\begin{refnotes} +The \OpenGL\ context is guaranteed to be preserved after calling +\textbf{glfwSetWindowSize}, even if the video mode is changed. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwSetWindowPos} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwSetWindowPos( int x, int y ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{x}]\ \\ + Horizontal position of the window, relative to the upper left corner + of the desktop. +\item [\textit{y}]\ \\ + Vertical position of the window, relative to the upper left corner of + the desktop. +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function changes the position of an opened window. It does not have +any effect on a fullscreen window. +\end{refdescription} + + +%------------------------------------------------------------------------- +\subsection{glfwGetWindowSize} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwGetWindowSize( int *width, int *height ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{width}]\ \\ + Pointer to an integer that will hold the width of the window. +\item [\textit{height}]\ \\ + Pointer to an integer that will hold the height of the window. +\end{description} +\end{refparameters} + +\begin{refreturn} +The current width and height of the opened window is returned in the +\textit{width} and \textit{height} parameters, respectively. +\end{refreturn} + +\begin{refdescription} +The function is used for determining the size of an opened window. +The returned values are dimensions of the client area of the window +(i.e. excluding any window borders and decorations). +\end{refdescription} + +\begin{refnotes} +Even if the size of a fullscreen window does not change once the window +has been opened, it does not necessarily have to be the same as the size +that was requested using \textbf{glfwOpenWindow}. Therefor it is wise to +use this function to determine the true size of the window once it has +been opened. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwSetWindowSizeCallback} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwSetWindowSizeCallback( GLFWwindowsizefun cbfun ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{cbfun}]\ \\ + Pointer to a callback function that will be called every time the + window size changes. The function should have the following C language + prototype: + + \texttt{void GLFWCALL functionname( int width, int height );} + + Where \textit{functionname} is the name of the callback function, and + \textit{width} and \textit{height} are the dimensions of the window + client area. + + If \textit{cbfun} is NULL, any previously selected callback function + will be deselected. +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function selects which function to be called upon a window size +change event. + +A window has to be opened for this function to have any effect. +\end{refdescription} + +\begin{refnotes} +Window size changes are recorded continuously, but only reported when +\textbf{glfwPollEvents}, \textbf{glfwWaitEvents} or +\textbf{glfwSwapBuffers} is called. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwIconifyWindow} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwIconifyWindow( void ) +\end{lstlisting} + +\begin{refparameters} +none +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +Iconify a window. If the window is in fullscreen mode, then the desktop +video mode will be restored. +\end{refdescription} + + +%------------------------------------------------------------------------- +\subsection{glfwRestoreWindow} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwRestoreWindow( void ) +\end{lstlisting} + +\begin{refparameters} +none +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +Restore an iconified window. If the window that is restored is in +fullscreen mode, then the fullscreen video mode will be restored. +\end{refdescription} + + +%------------------------------------------------------------------------- +\begin{table}[p] +\begin{center} +\begin{tabular}{|l|p{9.5cm}|} \hline \raggedright +\textbf{Name} & \textbf{Description} \\ \hline +GLFW\_OPENED & GL\_TRUE if window is opened, else GL\_FALSE.\\ \hline +GLFW\_ACTIVE & GL\_TRUE if window has focus, else GL\_FALSE.\\ \hline +GLFW\_ICONIFIED & GL\_TRUE if window is iconified, else GL\_FALSE.\\ \hline +GLFW\_ACCELERATED & GL\_TRUE if window is hardware accelerated, else GL\_FALSE.\\ \hline +GLFW\_RED\_BITS & Number of bits for the red color component.\\ \hline +GLFW\_GREEN\_BITS & Number of bits for the green color component.\\ \hline +GLFW\_BLUE\_BITS & Number of bits for the blue color component.\\ \hline +GLFW\_ALPHA\_BITS & Number of bits for the alpha buffer.\\ \hline +GLFW\_DEPTH\_BITS & Number of bits for the depth buffer.\\ \hline +GLFW\_STENCIL\_BITS & Number of bits for the stencil buffer.\\ \hline +GLFW\_REFRESH\_RATE & Vertical monitor refresh rate in Hz. Zero indicates an unknown or a default refresh rate.\\ \hline +GLFW\_ACCUM\_RED\_BITS & Number of bits for the red channel of the accumulator buffer.\\ \hline +GLFW\_ACCUM\_GREEN\_BITS & Number of bits for the green channel of the accumulator buffer.\\ \hline +GLFW\_ACCUM\_BLUE\_BITS & Number of bits for the blue channel of the accumulator buffer.\\ \hline +GLFW\_ACCUM\_ALPHA\_BITS & Number of bits for the alpha channel of the accumulator buffer.\\ \hline +GLFW\_AUX\_BUFFERS & Number of auxiliary buffers.\\ \hline +GLFW\_STEREO & GL\_TRUE if stereo rendering is supported, else GL\_FALSE.\\ \hline +GLFW\_WINDOW\_NO\_RESIZE & GL\_TRUE if the window cannot be resized, else GL\_FALSE.\\ \hline +GLFW\_FSAA\_SAMPLES & Number of multisampling buffer samples. Zero indicated multisampling is disabled.\\ \hline +GLFW\_OPENGL\_VERSION\_MAJOR & Major number of the desired OpenGL version.\\ \hline +GLFW\_OPENGL\_VERSION\_MINOR & Minor number of the desired OpenGL version.\\ \hline +GLFW\_OPENGL\_FORWARD\_COMPAT & GL\_TRUE if the OpenGL context is forward compatible (i.e. disallows legacy functionality), else GL\_FALSE. +This is always GL\_FALSE for OpenGL version 2.1 and below.\\ \hline +\end{tabular} +\end{center} +\caption{Window parameters for \textbf{glfwGetWindowParam}} +\label{tab:winparams} +\end{table} + + +%------------------------------------------------------------------------- +\subsection{glfwGetWindowParam} + +\textbf{C language syntax} +\begin{lstlisting} +int glfwGetWindowParam( int param ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{param}]\ \\ + A token selecting which parameter the function should return (see + table \ref{tab:winparams}). +\end{description} +\end{refparameters} + +\begin{refreturn} +The function returns different parameters depending on the value of +\textit{param}. Table \ref{tab:winparams} lists valid \textit{param} +values, and their corresponding return values. +\end{refreturn} + +\begin{refdescription} +The function is used for acquiring various properties of an opened window. +\end{refdescription} + +\begin{refnotes} +GLFW\_ACCELERATED is only supported under Windows. Other systems will +always return GL\_TRUE. Under Windows, GLFW\_ACCELERATED means that the +\OpenGL\ renderer is a 3rd party renderer, rather than the fallback +Microsoft software \OpenGL\ renderer. In other words, it is not a real +guarantee that the \OpenGL\ renderer is actually hardware accelerated. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwSwapBuffers} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwSwapBuffers( void ) +\end{lstlisting} + +\begin{refparameters} +none +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function swaps the back and front color buffers of the window. If +GLFW\_AUTO\_POLL\_EVENTS is enabled (which is the default), +\textbf{glfwPollEvents} is called before swapping the front and back +buffers. +\end{refdescription} + + +%------------------------------------------------------------------------- +\subsection{glfwSwapInterval} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwSwapInterval( int interval ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{interval}]\ \\ + Minimum number of monitor vertical retraces between each buffer swap + performed by \textbf{glfwSwapBuffers}. If \textit{interval} is zero, + buffer swaps will not be synchronized to the vertical refresh of the + monitor (also known as 'VSync off'). +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function selects the minimum number of monitor vertical retraces that +should occur between two buffer swaps. If the selected swap interval is +one, the rate of buffer swaps will never be higher than the vertical +refresh rate of the monitor. If the selected swap interval is zero, the +rate of buffer swaps is only limited by the speed of the software and +the hardware. +\end{refdescription} + +\begin{refnotes} +This function will only have an effect on hardware and drivers that +support user selection of the swap interval. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwSetWindowRefreshCallback} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwSetWindowRefreshCallback( GLFWwindowrefreshfun cbfun ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{cbfun}]\ \\ + Pointer to a callback function that will be called when the window client + area needs to be refreshed. The function should have the following C + language prototype: + + \texttt{void GLFWCALL functionname( void );} + + Where \textit{functionname} is the name of the callback function. + + If \textit{cbfun} is NULL, any previously selected callback function + will be deselected. +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function selects which function to be called upon a window refresh +event, which occurs when any part of the window client area has been +damaged, and needs to be repainted (for instance, if a part of the window +that was previously occluded by another window has become visible). + +A window has to be opened for this function to have any effect. +\end{refdescription} + +\begin{refnotes} +Window refresh events are recorded continuously, but only reported when +\textbf{glfwPollEvents}, \textbf{glfwWaitEvents} or +\textbf{glfwSwapBuffers} is called. +\end{refnotes} + + +%------------------------------------------------------------------------- +\pagebreak +\section{Video Modes} +Since \GLFW\ supports video mode changes when using a fullscreen window, +it also provides functionality for querying which video modes are +supported on a system. + + +%------------------------------------------------------------------------- +\subsection{glfwGetVideoModes} + +\textbf{C language syntax} +\begin{lstlisting} +int glfwGetVideoModes( GLFWvidmode *list, int maxcount ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{list}]\ \\ + A vector of \textit{GLFWvidmode} structures, which will be filled out + by the function. +\item [\textit{maxcount}]\ \\ + Maximum number of video modes that \textit{list} vector can hold. +\end{description} +\end{refparameters} + +\begin{refreturn} +The function returns the number of detected video modes (this number +will never exceed \textit{maxcount}). The \textit{list} vector is +filled out with the video modes that are supported by the system. +\end{refreturn} + +\begin{refdescription} +The function returns a list of supported video modes. Each video mode is +represented by a \textit{GLFWvidmode} structure, which has the following +definition: + +\begin{lstlisting} +typedef struct { + int Width, Height; // Video resolution + int RedBits; // Number of red bits + int GreenBits; // Number of green bits + int BlueBits; // Number of blue bits +} GLFWvidmode; +\end{lstlisting} +\end{refdescription} + +\begin{refnotes} +The returned list is sorted, first by color depth ($RedBits + GreenBits + +BlueBits$), and then by resolution ($Width \times Height$), with the +lowest resolution, fewest bits per pixel mode first. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwGetDesktopMode} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwGetDesktopMode( GLFWvidmode *mode ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{mode}]\ \\ + Pointer to a \textit{GLFWvidmode} structure, which will be filled out + by the function. +\end{description} +\end{refparameters} + +\begin{refreturn} +The \textit{GLFWvidmode} structure pointed to by \textit{mode} is filled +out with the desktop video mode. +\end{refreturn} + +\begin{refdescription} +The function returns the desktop video mode in a \textit{GLFWvidmode} +structure. See \textbf{glfwGetVideoModes} for a definition of the +\textit{GLFWvidmode} structure. +\end{refdescription} + +\begin{refnotes} +The color depth of the desktop display is always reported as the number +of bits for each individual color component (red, green and blue), even +if the desktop is not using an RGB or RGBA color format. For instance, an +indexed 256 color display may report \textit{RedBits} = 3, +\textit{GreenBits} = 3 and \textit{BlueBits} = 2, which adds up to 8 bits +in total. + +The desktop video mode is the video mode used by the desktop, \textit{not} +the current video mode (which may differ from the desktop video mode if +the \GLFW\ window is a fullscreen window). +\end{refnotes} + + +%------------------------------------------------------------------------- +\pagebreak +\section{Input Handling} +\GLFW\ supports three channels of user input: keyboard input, mouse input +and joystick input. + +Keyboard and mouse input can be treated either as events, using callback +functions, or as state, using functions for polling specific keyboard and +mouse states. Regardless of which method is used, all keyboard and mouse +input is collected using window event polling. + +Joystick input is asynchronous to the keyboard and mouse input, and does +not require event polling for keeping up to date joystick information. +Also, joystick input is independent of any window, so a window does not +have to be opened for joystick input to be used. + + +%------------------------------------------------------------------------- +\subsection{glfwPollEvents} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwPollEvents( void ) +\end{lstlisting} + +\begin{refparameters} +none +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function is used for polling for events, such as user input and +window resize events. Upon calling this function, all window states, +keyboard states and mouse states are updated. If any related callback +functions are registered, these are called during the call to +\textbf{glfwPollEvents}. +\end{refdescription} + +\begin{refnotes} +\textbf{glfwPollEvents} is called implicitly from \textbf{glfwSwapBuffers} +if GLFW\_AUTO\_POLL\_EVENTS is enabled (default). Thus, if +\textbf{glfwSwapBuffers} is called frequently, which is normally the case, +there is no need to call \textbf{glfwPollEvents}. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwWaitEvents} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwWaitEvents( void ) +\end{lstlisting} + +\begin{refparameters} +none +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function is used for waiting for events, such as user input and +window resize events. Upon calling this function, the calling thread will +be put to sleep until any event appears in the event queue. When events +are ready, the events will be processed just as they are processed by +\textbf{glfwPollEvents}. + +If there are any events in the queue when the function is called, the +function will behave exactly like \textbf{glfwPollEvents} (i.e. process +all messages and then return, without blocking the calling thread). +\end{refdescription} + +\begin{refnotes} +It is guaranteed that \textbf{glfwWaitEvents} will wake up on any event +that can be processed by \textbf{glfwPollEvents}. However, +\textbf{glfwWaitEvents} may wake up on events that are \emph{not} +processed or reported by \textbf{glfwPollEvents} too, and the function +may behave differently on different systems. Do not make any assumptions +about when or why \textbf{glfwWaitEvents} will return. +\end{refnotes} + + +%------------------------------------------------------------------------- +\begin{table}[p] +\begin{center} +\begin{tabular}{|l|l|} \hline \raggedright +\textbf{Name} & \textbf{Description} \\ \hline +GLFW\_KEY\_SPACE & Space\\ \hline +GLFW\_KEY\_ESC & Escape\\ \hline +GLFW\_KEY\_F\textit{n} & Function key \textit{n} (\textit{n} can be in the range 1..25)\\ \hline +GLFW\_KEY\_UP & Cursor up\\ \hline +GLFW\_KEY\_DOWN & Cursor down\\ \hline +GLFW\_KEY\_LEFT & Cursor left\\ \hline +GLFW\_KEY\_RIGHT & Cursor right\\ \hline +GLFW\_KEY\_LSHIFT & Left shift key\\ \hline +GLFW\_KEY\_RSHIFT & Right shift key\\ \hline +GLFW\_KEY\_LCTRL & Left control key\\ \hline +GLFW\_KEY\_RCTRL & Right control key\\ \hline +GLFW\_KEY\_LALT & Left alternate function key\\ \hline +GLFW\_KEY\_RALT & Right alternate function key\\ \hline +GLFW\_KEY\_TAB & Tabulator\\ \hline +GLFW\_KEY\_ENTER & Enter\\ \hline +GLFW\_KEY\_BACKSPACE & Backspace\\ \hline +GLFW\_KEY\_INSERT & Insert\\ \hline +GLFW\_KEY\_DEL & Delete\\ \hline +GLFW\_KEY\_PAGEUP & Page up\\ \hline +GLFW\_KEY\_PAGEDOWN & Page down\\ \hline +GLFW\_KEY\_HOME & Home\\ \hline +GLFW\_KEY\_END & End\\ \hline +GLFW\_KEY\_KP\_\textit{n} & Keypad numeric key \textit{n} (\textit{n} can be in the range 0..9)\\ \hline +GLFW\_KEY\_KP\_DIVIDE & Keypad divide ($\div$)\\ \hline +GLFW\_KEY\_KP\_MULTIPLY & Keypad multiply ($\times$)\\ \hline +GLFW\_KEY\_KP\_SUBTRACT & Keypad subtract ($-$)\\ \hline +GLFW\_KEY\_KP\_ADD & Keypad add ($+$)\\ \hline +GLFW\_KEY\_KP\_DECIMAL & Keypad decimal (. or ,)\\ \hline +GLFW\_KEY\_KP\_EQUAL & Keypad equal (=)\\ \hline +GLFW\_KEY\_KP\_ENTER & Keypad enter\\ \hline +\end{tabular} +\end{center} +\caption{Special key identifiers} +\label{tab:keys} +\end{table} + + +%------------------------------------------------------------------------- +\begin{table}[p] +\begin{center} +\begin{tabular}{|l|l|} \hline \raggedright +\textbf{Name} & \textbf{Description} \\ \hline +GLFW\_MOUSE\_BUTTON\_LEFT & Left mouse button (button 1) \\ \hline +GLFW\_MOUSE\_BUTTON\_RIGHT & Right mouse button (button 2) \\ \hline +GLFW\_MOUSE\_BUTTON\_MIDDLE & Middle mouse button (button 3) \\ \hline +GLFW\_MOUSE\_BUTTON\_\textit{n} & Mouse button \textit{n} (\textit{n} can be in the range 1..8)\\ \hline +\end{tabular} +\end{center} +\caption{Valid mouse button identifiers} +\label{tab:mousebuttons} +\end{table} + + +%------------------------------------------------------------------------- +\subsection{glfwGetKey} + +\textbf{C language syntax} +\begin{lstlisting} +int glfwGetKey( int key ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{key}]\ \\ + A keyboard key identifier, which can be either an uppercase printable + ISO~8859-1 (Latin~1) character (e.g. 'A', '3' or '.'), or a special key + identifier. Table \ref{tab:keys} lists valid special key identifiers. +\end{description} +\end{refparameters} + +\begin{refreturn} +The function returns GLFW\_PRESS if the key is held down, or GLFW\_RELEASE +if the key is not held down. +\end{refreturn} + +\begin{refdescription} +The function queries the current state of a specific keyboard key. The +physical location of each key depends on the system keyboard layout +setting. +\end{refdescription} + +\begin{refnotes} +The constant GLFW\_KEY\_SPACE is equal to 32, which is the ISO~8859-1 code +for space. + +Not all key codes are supported on all systems. Also, while some keys are +available on some keyboard layouts, they may not be available on other +keyboard layouts. + +For systems that do not distinguish between left and right versions of +modifier keys (shift, alt and control), the left version is used (e.g. +GLFW\_KEY\_LSHIFT). + +A window must be opened for the function to have any effect, and +\textbf{glfwPollEvents}, \textbf{glfwWaitEvents} or +\textbf{glfwSwapBuffers} must be called before any keyboard events are +recorded and reported by \textbf{glfwGetKey}. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwGetMouseButton} + +\textbf{C language syntax} +\begin{lstlisting} +int glfwGetMouseButton( int button ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{button}]\ \\ + A mouse button identifier, which can be one of the mouse button + identifiers listed in table \ref{tab:mousebuttons}. +\end{description} +\end{refparameters} + +\begin{refreturn} +The function returns GLFW\_PRESS if the mouse button is held down, or +GLFW\_RELEASE if the mouse button is not held down. +\end{refreturn} + +\begin{refdescription} +The function queries the current state of a specific mouse button. +\end{refdescription} + +\begin{refnotes} +A window must be opened for the function to have any effect, and +\textbf{glfwPollEvents}, \textbf{glfwWaitEvents} or +\textbf{glfwSwapBuffers} must be called before any mouse button events +are recorded and reported by \textbf{glfwGetMouseButton}. + +GLFW\_MOUSE\_BUTTON\_LEFT is equal to GLFW\_MOUSE\_BUTTON\_1. +GLFW\_MOUSE\_BUTTON\_RIGHT is equal to GLFW\_MOUSE\_BUTTON\_2. +GLFW\_MOUSE\_BUTTON\_MIDDLE is equal to GLFW\_MOUSE\_BUTTON\_3. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwGetMousePos} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwGetMousePos( int *xpos, int *ypos ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{xpos}]\ \\ + Pointer to an integer that will be filled out with the horizontal + position of the mouse. +\item [\textit{ypos}]\ \\ + Pointer to an integer that will be filled out with the vertical + position of the mouse. +\end{description} +\end{refparameters} + +\begin{refreturn} +The function returns the current mouse position in \textit{xpos} and +\textit{ypos}. +\end{refreturn} + +\begin{refdescription} +The function returns the current mouse position. If the cursor is not +hidden, the mouse position is the cursor position, relative to the upper +left corner of the window and limited to the client area of the window. +If the cursor is hidden, the mouse position is a virtual absolute +position, not limited to any boundaries except to those implied by the +maximum number that can be represented by a signed integer (normally +-2147483648 to +2147483647). +\end{refdescription} + +\begin{refnotes} +A window must be opened for the function to have any effect, and +\textbf{glfwPollEvents}, \textbf{glfwWaitEvents} or +\textbf{glfwSwapBuffers} must be called before any mouse movements are +recorded and reported by \textbf{glfwGetMousePos}. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwSetMousePos} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwSetMousePos( int xpos, int ypos ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{xpos}]\ \\ + Horizontal position of the mouse. +\item [\textit{ypos}]\ \\ + Vertical position of the mouse. +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function changes the position of the mouse. If the cursor is +visible (not disabled), the cursor will be moved to the specified +position, relative to the upper left corner of the window client area. +If the cursor is hidden (disabled), only the mouse position that is +reported by \GLFW\ is changed. +\end{refdescription} + + +%------------------------------------------------------------------------- +\subsection{glfwGetMouseWheel} + +\textbf{C language syntax} +\begin{lstlisting} +int glfwGetMouseWheel( void ) +\end{lstlisting} + +\begin{refparameters} +none +\end{refparameters} + +\begin{refreturn} +The function returns the current mouse wheel position. +\end{refreturn} + +\begin{refdescription} +The function returns the current mouse wheel position. The mouse wheel can +be thought of as a third mouse axis, which is available as a separate +wheel or up/down stick on some mice. +\end{refdescription} + +\begin{refnotes} +A window must be opened for the function to have any effect, and +\textbf{glfwPollEvents}, \textbf{glfwWaitEvents} or +\textbf{glfwSwapBuffers} must be called before any mouse wheel movements +are recorded and reported by \textbf{glfwGetMouseWheel}. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwSetMouseWheel} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwSetMouseWheel( int pos ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{pos}]\ \\ + Position of the mouse wheel. +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function changes the position of the mouse wheel. +\end{refdescription} + + +%------------------------------------------------------------------------- +\subsection{glfwSetKeyCallback} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwSetKeyCallback( GLFWkeyfun cbfun ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{cbfun}]\ \\ + Pointer to a callback function that will be called every time a key is + pressed or released. The function should have the following C language + prototype: + + \texttt{void GLFWCALL functionname( int key, int action );} + + Where \textit{functionname} is the name of the callback function, + \textit{key} is a key identifier, which is an uppercase printable + ISO~8859-1 character or a special key identifier (see table + \ref{tab:keys}), and \textit{action} is either GLFW\_PRESS or + GLFW\_RELEASE. + + If \textit{cbfun} is NULL, any previously selected callback function + will be deselected. +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function selects which function to be called upon a keyboard key +event. The callback function is called every time the state of a single +key is changed (from released to pressed or vice versa). The reported keys +are unaffected by any modifiers (such as shift or alt). + +A window has to be opened for this function to have any effect. +\end{refdescription} + +\begin{refnotes} +Keyboard events are recorded continuously, but only reported when +\textbf{glfwPollEvents}, \textbf{glfwWaitEvents} or +\textbf{glfwSwapBuffers} is called. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwSetCharCallback} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwSetCharCallback( GLFWcharfun cbfun ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{cbfun}]\ \\ + Pointer to a callback function that will be called every time a + printable character is generated by the keyboard. The function should + have the following C language prototype: + + \texttt{void GLFWCALL functionname( int character, int action );} + + Where \textit{functionname} is the name of the callback function, + \textit{character} is a Unicode (ISO~10646) character, and + \textit{action} is either GLFW\_PRESS or GLFW\_RELEASE. + + If \textit{cbfun} is NULL, any previously selected callback function + will be deselected. +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function selects which function to be called upon a keyboard character +event. The callback function is called every time a key that results in a +printable Unicode character is pressed or released. Characters are +affected by modifiers (such as shift or alt). + +A window has to be opened for this function to have any effect. +\end{refdescription} + +\begin{refnotes} +Character events are recorded continuously, but only reported when +\textbf{glfwPollEvents}, \textbf{glfwWaitEvents} or +\textbf{glfwSwapBuffers} is called. + +Control characters, such as tab and carriage return, are not reported to +the character callback function, since they are not part of the Unicode +character set. Use the key callback function for such events (see +\textbf{glfwSetKeyCallback}). + +The Unicode character set supports character codes above 255, so never +cast a Unicode character to an eight bit data type (e.g. the C language +'char' type) without first checking that the character code is less than +256. Also note that Unicode character codes 0 to 255 are equal to +ISO~8859-1 (Latin~1). +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwSetMouseButtonCallback} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwSetMouseButtonCallback( GLFWmousebuttonfun cbfun ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{cbfun}]\ \\ + Pointer to a callback function that will be called every time a mouse + button is pressed or released. The function should have the following C + language prototype: + + \texttt{void GLFWCALL functionname( int button, int action );} + + Where \textit{functionname} is the name of the callback function, + \textit{button} is a mouse button identifier (see table + \ref{tab:mousebuttons} on page \pageref{tab:mousebuttons}), and + \textit{action} is either GLFW\_PRESS or GLFW\_RELEASE. + + If \textit{cbfun} is NULL, any previously selected callback function + will be deselected. +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function selects which function to be called upon a mouse button +event. + +A window has to be opened for this function to have any effect. +\end{refdescription} + +\begin{refnotes} +Mouse button events are recorded continuously, but only reported when +\textbf{glfwPollEvents}, \textbf{glfwWaitEvents} or +\textbf{glfwSwapBuffers} is called. + +GLFW\_MOUSE\_BUTTON\_LEFT is equal to GLFW\_MOUSE\_BUTTON\_1. +GLFW\_MOUSE\_BUTTON\_RIGHT is equal to GLFW\_MOUSE\_BUTTON\_2. +GLFW\_MOUSE\_BUTTON\_MIDDLE is equal to GLFW\_MOUSE\_BUTTON\_3. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwSetMousePosCallback} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwSetMousePosCallback( GLFWmouseposfun cbfun ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{cbfun}]\ \\ + Pointer to a callback function that will be called every time the mouse + is moved. The function should have the following C language prototype: + + \texttt{void GLFWCALL functionname( int x, int y );} + + Where \textit{functionname} is the name of the callback function, and + \textit{x} and \textit{y} are the mouse coordinates (see + \textbf{glfwGetMousePos} for more information on mouse coordinates). + + If \textit{cbfun} is NULL, any previously selected callback function + will be deselected. +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function selects which function to be called upon a mouse motion event. + +A window has to be opened for this function to have any effect. +\end{refdescription} + +\begin{refnotes} +Mouse motion events are recorded continuously, but only reported when +\textbf{glfwPollEvents}, \textbf{glfwWaitEvents} or +\textbf{glfwSwapBuffers} is called. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwSetMouseWheelCallback} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwSetMouseWheelCallback( GLFWmousewheelfun cbfun ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{cbfun}]\ \\ + Pointer to a callback function that will be called every time the mouse + wheel is moved. The function should have the following C language + prototype: + + \texttt{void GLFWCALL functionname( int pos );} + + Where \textit{functionname} is the name of the callback function, and + \textit{pos} is the mouse wheel position. + + If \textit{cbfun} is NULL, any previously selected callback function + will be deselected. +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function selects which function to be called upon a mouse wheel event. + +A window has to be opened for this function to have any effect. +\end{refdescription} + +\begin{refnotes} +Mouse wheel events are recorded continuously, but only reported when +\textbf{glfwPollEvents}, \textbf{glfwWaitEvents} or +\textbf{glfwSwapBuffers} is called. +\end{refnotes} + + +%------------------------------------------------------------------------- +\begin{table}[p] +\begin{center} +\begin{tabular}{|l|l|}\hline \raggedright +\textbf{Name} & \textbf{Return value}\\ \hline +GLFW\_PRESENT & GL\_TRUE if the joystick is connected, else GL\_FALSE.\\ \hline +GLFW\_AXES & Number of axes supported by the joystick.\\ \hline +GLFW\_BUTTONS & Number of buttons supported by the joystick.\\ \hline +\end{tabular} +\end{center} +\caption{Joystick parameters for \textbf{glfwGetJoystickParam}} +\label{tab:joyparams} +\end{table} + + +%------------------------------------------------------------------------- +\subsection{glfwGetJoystickParam} + +\textbf{C language syntax} +\begin{lstlisting} +int glfwGetJoystickParam( int joy, int param ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{joy}]\ \\ + A joystick identifier, which should be GLFW\_JOYSTICK\_\textit{n}, where + \textit{n} is in the range 1 to 16. +\item [\textit{param}]\ \\ + A token selecting which parameter the function should return (see table + \ref{tab:joyparams}). +\end{description} +\end{refparameters} + +\begin{refreturn} +The function returns different parameters depending on the value of +\textit{param}. Table \ref{tab:joyparams} lists valid \textit{param} +values, and their corresponding return values. +\end{refreturn} + +\begin{refdescription} +The function is used for acquiring various properties of a joystick. +\end{refdescription} + +\begin{refnotes} +The joystick information is updated every time the function is called. + +No window has to be opened for joystick information to be valid. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwGetJoystickPos} + +\textbf{C language syntax} +\begin{lstlisting} +int glfwGetJoystickPos( int joy, float *pos, int numaxes ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{joy}]\ \\ + A joystick identifier, which should be GLFW\_JOYSTICK\_\textit{n}, where + \textit{n} is in the range 1 to 16. +\item [\textit{pos}]\ \\ + An array that will hold the positional values for all requested axes. +\item [\textit{numaxes}]\ \\ + Specifies how many axes should be returned. +\end{description} +\end{refparameters} + +\begin{refreturn} +The function returns the number of actually returned axes. This is the +minimum of \textit{numaxes} and the number of axes supported by the +joystick. If the joystick is not supported or connected, the function will +return 0 (zero). +\end{refreturn} + +\begin{refdescription} +The function queries the current position of one or more axes of a +joystick. The positional values are returned in an array, where the first +element represents the first axis of the joystick (normally the X axis). +Each position is in the range -1.0 to 1.0. Where applicable, the positive +direction of an axis is right, forward or up, and the negative direction +is left, back or down. + +If \textit{numaxes} exceeds the number of axes supported by the joystick, +or if the joystick is not available, the unused elements in the +\textit{pos} array will be set to 0.0 (zero). +\end{refdescription} + +\begin{refnotes} +The joystick state is updated every time the function is called, so there +is no need to call \textbf{glfwPollEvents} or \textbf{glfwWaitEvents} for +joystick state to be updated. + +Use \textbf{glfwGetJoystickParam} to retrieve joystick capabilities, such +as joystick availability and number of supported axes. + +No window has to be opened for joystick input to be valid. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwGetJoystickButtons} + +\textbf{C language syntax} +\begin{lstlisting} +int glfwGetJoystickButtons( int joy, unsigned char *buttons, + int numbuttons ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{joy}]\ \\ + A joystick identifier, which should be GLFW\_JOYSTICK\_\textit{n}, where + \textit{n} is in the range 1 to 16. +\item [\textit{buttons}]\ \\ + An array that will hold the button states for all requested buttons. +\item [\textit{numbuttons}]\ \\ + Specifies how many buttons should be returned. +\end{description} +\end{refparameters} + +\begin{refreturn} +The function returns the number of actually returned buttons. This is the +minimum of \textit{numbuttons} and the number of buttons supported by the +joystick. If the joystick is not supported or connected, the function will +return 0 (zero). +\end{refreturn} + +\begin{refdescription} +The function queries the current state of one or more buttons of a +joystick. The button states are returned in an array, where the first +element represents the first button of the joystick. Each state can be +either GLFW\_PRESS or GLFW\_RELEASE. + +If \textit{numbuttons} exceeds the number of buttons supported by the +joystick, or if the joystick is not available, the unused elements in the +\textit{buttons} array will be set to GLFW\_RELEASE. +\end{refdescription} + +\begin{refnotes} +The joystick state is updated every time the function is called, so there +is no need to call \textbf{glfwPollEvents} or \textbf{glfwWaitEvents} for +joystick state to be updated. + +Use \textbf{glfwGetJoystickParam} to retrieve joystick capabilities, such +as joystick availability and number of supported buttons. + +No window has to be opened for joystick input to be valid. +\end{refnotes} + + +%------------------------------------------------------------------------- +\pagebreak +\section{Timing} + +%------------------------------------------------------------------------- +\subsection{glfwGetTime} + +\textbf{C language syntax} +\begin{lstlisting} +double glfwGetTime( void ) +\end{lstlisting} + +\begin{refparameters} +none +\end{refparameters} + +\begin{refreturn} +The function returns the value of the high precision timer. The time is +measured in seconds, and is returned as a double precision floating point +value. +\end{refreturn} + +\begin{refdescription} +The function returns the state of a high precision timer. Unless the timer +has been set by the \textbf{glfwSetTime} function, the time is measured as +the number of seconds that have passed since \textbf{glfwInit} was called. +\end{refdescription} + +\begin{refnotes} +The resolution of the timer depends on which system the program is running +on. The worst case resolution is somewhere in the order of $10~ms$, while +for most systems the resolution should be better than $1~\mu s$. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwSetTime} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwSetTime( double time ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{time}]\ \\ + Time (in seconds) that the timer should be set to. +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +The function sets the current time of the high precision timer to the +specified time. Subsequent calls to \textbf{glfwGetTime} will be relative +to this time. The time is given in seconds. +\end{refdescription} + + +%------------------------------------------------------------------------- +\pagebreak +\section{OpenGL Extension Support} +One of the great features of \OpenGL\ is its support for extensions, which +allow independent vendors to supply non-standard functionality in their +\OpenGL\ implementations. Using extensions is different under different +systems, which is why \GLFW\ has provided an operating system independent +interface to querying and using \OpenGL\ extensions. + + +%------------------------------------------------------------------------- +\subsection{glfwExtensionSupported} + +\textbf{C language syntax} +\begin{lstlisting} +int glfwExtensionSupported( const char *extension ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{extension}]\ \\ + A null terminated ISO~8859-1 string containing the name of an \OpenGL\ + extension. +\end{description} +\end{refparameters} + +\begin{refreturn} +The function returns GL\_TRUE if the extension is supported. Otherwise it +returns GL\_FALSE. +\end{refreturn} + +\begin{refdescription} +The function does a string search in the list of supported \OpenGL\ +extensions to find if the specified extension is listed. +\end{refdescription} + +\begin{refnotes} +An \OpenGL\ context must be created before this function can be called +(i.e. an \OpenGL\ window must have been opened with +\textbf{glfwOpenWindow}). + +In addition to checking for \OpenGL\ extensions, \GLFW\ also checks for +extensions in the operating system ``glue API'', such as WGL extensions +under Windows and glX extensions under the X Window System. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwGetProcAddress} + +\textbf{C language syntax} +\begin{lstlisting} +void * glfwGetProcAddress( const char *procname ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{procname}]\ \\ + A null terminated ISO~8859-1 string containing the name of an \OpenGL\ + extension function. +\end{description} +\end{refparameters} + +\begin{refreturn} +The function returns the pointer to the specified \OpenGL\ function if it +is supported, otherwise NULL is returned. +\end{refreturn} + +\begin{refdescription} +The function acquires the pointer to an \OpenGL\ extension function. Some +(but not all) \OpenGL\ extensions define new API functions, which are +usually not available through normal linking. It is therefore necessary to +get access to those API functions at runtime. +\end{refdescription} + +\begin{refnotes} +An \OpenGL\ context must be created before this function can be called +(i.e. an \OpenGL\ window must have been opened with +\textbf{glfwOpenWindow}). + +Some systems do not support dynamic function pointer retrieval, in which +case \textbf{glfwGetProcAddress} will always return NULL. +\end{refnotes} + + +%------------------------------------------------------------------------- +\subsection{glfwGetGLVersion} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwGetGLVersion( int *major, int *minor, int *rev ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{major}]\ \\ + Pointer to an integer that will hold the major version number. +\item [\textit{minor}]\ \\ + Pointer to an integer that will hold the minor version number. +\item [\textit{rev}]\ \\ + Pointer to an integer that will hold the revision. +\end{description} +\end{refparameters} + +\begin{refreturn} +The function returns the major and minor version numbers and the revision +for the currently used \OpenGL\ implementation. +\end{refreturn} + +\begin{refdescription} +The function returns the \OpenGL\ implementation version. This is a +convenient function that parses the version number information from the +string returned by calling \texttt{glGetString(~GL\_VERSION~)}. The +\OpenGL\ version information can be used to determine what functionality +is supported by the used \OpenGL\ implementation. +\end{refdescription} + +\begin{refnotes} +An \OpenGL\ context must be created before this function can be called +(i.e. an \OpenGL\ window must have been opened with +\textbf{glfwOpenWindow}). +\end{refnotes} + + +%------------------------------------------------------------------------- +\pagebreak +\section{Miscellaneous} + + +%------------------------------------------------------------------------- +\subsection{glfwEnable/glfwDisable} + +\textbf{C language syntax} +\begin{lstlisting} +void glfwEnable( int token ) +void glfwDisable( int token ) +\end{lstlisting} + +\begin{refparameters} +\begin{description} +\item [\textit{token}]\ \\ + A value specifying a feature to enable or disable. Valid tokens are + listed in table \ref{tab:enable}. +\end{description} +\end{refparameters} + +\begin{refreturn} +none +\end{refreturn} + +\begin{refdescription} +\textbf{glfwEnable} is used to enable a certain feature, while +\textbf{glfwDisable} is used to disable it. Below follows a description of +each feature. +\end{refdescription} + + +\begin{table}[p] +\begin{center} +\begin{tabular}{|l|p{5.0cm}|p{3.0cm}|} \hline \raggedright +\textbf{Name} & \textbf{Controls} & \textbf{Default}\\ \hline +\hyperlink{lnk:autopollevents}{GLFW\_AUTO\_POLL\_EVENTS} & Automatic event polling when \textbf{glfwSwapBuffers} is called & Enabled\\ \hline +\hyperlink{lnk:keyrepeat}{GLFW\_KEY\_REPEAT} & Keyboard key repeat & Disabled\\ \hline +\hyperlink{lnk:mousecursor}{GLFW\_MOUSE\_CURSOR} & Mouse cursor visibility & Enabled in windowed mode. Disabled in fullscreen mode.\\ \hline +\hyperlink{lnk:stickykeys}{GLFW\_STICKY\_KEYS} & Keyboard key ``stickiness'' & Disabled\\ \hline +\hyperlink{lnk:stickymousebuttons}{GLFW\_STICKY\_MOUSE\_BUTTONS} & Mouse button ``stickiness'' & Disabled\\ \hline +\hyperlink{lnk:systemkeys}{GLFW\_SYSTEM\_KEYS} & Special system key actions & Enabled\\ \hline +\end{tabular} +\end{center} +\caption{Tokens for \textbf{glfwEnable}/\textbf{glfwDisable}} +\label{tab:enable} +\end{table} + + +\bigskip\begin{mysamepage}\hypertarget{lnk:autopollevents}{} +\textbf{GLFW\_AUTO\_POLL\_EVENTS}\\ +When GLFW\_AUTO\_POLL\_EVENTS is enabled, \textbf{glfwPollEvents} is +automatically called each time that \textbf{glfwSwapBuffers} is called. + +When GLFW\_AUTO\_POLL\_EVENTS is disabled, calling +\textbf{glfwSwapBuffers} will not result in a call to +\textbf{glfwPollEvents}. This can be useful if \textbf{glfwSwapBuffers} +needs to be called from within a callback function, since calling +\textbf{glfwPollEvents} from a callback function is not allowed. +\end{mysamepage} + + +\bigskip\begin{mysamepage}\hypertarget{lnk:keyrepeat}{} +\textbf{GLFW\_KEY\_REPEAT}\\ +When GLFW\_KEY\_REPEAT is enabled, the key and character callback +functions are called repeatedly when a key is held down long enough +(according to the system key repeat configuration). + +When GLFW\_KEY\_REPEAT is disabled, the key and character callback +functions are only called once when a key is pressed (and once when it is +released). +\end{mysamepage} + + +\bigskip\begin{mysamepage}\hypertarget{lnk:mousecursor}{} +\textbf{GLFW\_MOUSE\_CURSOR}\\ +When GLFW\_MOUSE\_CURSOR is enabled, the mouse cursor is visible, and +mouse coordinates are relative to the upper left corner of the client area +of the \GLFW\ window. The coordinates are limited to the client area of +the window. + +When GLFW\_MOUSE\_CURSOR is disabled, the mouse cursor is invisible, and +mouse coordinates are not limited to the drawing area of the window. It is +as if the mouse coordinates are recieved directly from the mouse, without +being restricted or manipulated by the windowing system. +\end{mysamepage} + + +\bigskip\begin{mysamepage}\hypertarget{lnk:stickykeys}{} +\textbf{GLFW\_STICKY\_KEYS}\\ +When GLFW\_STICKY\_KEYS is enabled, keys which are pressed will not be +released until they are physically released and checked with +\textbf{glfwGetKey}. This behavior makes it possible to catch keys that +were pressed and then released again between two calls to +\textbf{glfwPollEvents}, \textbf{glfwWaitEvents} or +\textbf{glfwSwapBuffers}, which would otherwise have been reported as +released. Care should be taken when using this mode, since keys that are +not checked with \textbf{glfwGetKey} will never be released. Note also +that enabling GLFW\_STICKY\_KEYS does not affect the behavior of the +keyboard callback functionality. + +When GLFW\_STICKY\_KEYS is disabled, the status of a key that is reported +by \textbf{glfwGetKey} is always the physical state of the key. Disabling +GLFW\_STICKY\_KEYS also clears the sticky information for all keys. +\end{mysamepage} + + +\bigskip\begin{mysamepage}\hypertarget{lnk:stickymousebuttons}{} +\textbf{GLFW\_STICKY\_MOUSE\_BUTTONS}\\ +When GLFW\_STICKY\_MOUSE\_BUTTONS is enabled, mouse buttons that are +pressed will not be released until they are physically released and +checked with \textbf{glfwGetMouseButton}. This behavior makes it +possible to catch mouse buttons which were pressed and then released again +between two calls to \textbf{glfwPollEvents}, \textbf{glfwWaitEvents} or +\textbf{glfwSwapBuffers}, which would otherwise have been reported as +released. Care should be taken when using this mode, since mouse buttons +that are not checked with \textbf{glfwGetMouseButton} will never be +released. Note also that enabling GLFW\_STICKY\_MOUSE\_BUTTONS does not +affect the behavior of the mouse button callback functionality. + +When GLFW\_STICKY\_MOUSE\_BUTTONS is disabled, the status of a mouse +button that is reported by \textbf{glfwGetMouseButton} is always the +physical state of the mouse button. Disabling GLFW\_STICKY\_MOUSE\_BUTTONS +also clears the sticky information for all mouse buttons. +\end{mysamepage} + + +\bigskip\begin{mysamepage}\hypertarget{lnk:systemkeys}{} +\textbf{GLFW\_SYSTEM\_KEYS}\\ +When GLFW\_SYSTEM\_KEYS is enabled, pressing standard system key +combinations, such as \texttt{ALT+TAB} under Windows, will give the normal +behavior. Note that when \texttt{ALT+TAB} is issued under Windows in this +mode so that the \GLFW\ application is deselected when \GLFW\ is operating +in fullscreen mode, the \GLFW\ application window will be minimized and +the video mode will be set to the original desktop mode. When the \GLFW\ +application is re-selected, the video mode will be set to the \GLFW\ video +mode again. + +When GLFW\_SYSTEM\_KEYS is disabled, pressing standard system key +combinations will have no effect, since those key combinations are blocked +by \GLFW . This mode can be useful in situations when the \GLFW\ program +must not be interrupted (normally for games in fullscreen mode). +\end{mysamepage} + + +\end{document} diff --git a/docs/glfwug.tex b/docs/glfwug.tex new file mode 100644 index 00000000..32a0359b --- /dev/null +++ b/docs/glfwug.tex @@ -0,0 +1,1287 @@ +%------------------------------------------------------------------------- +% GLFW Users Guide +% API Version: 2.7 +%------------------------------------------------------------------------- + +% Document class +\documentclass[a4paper,11pt,oneside]{report} + +% Document title and API version +\newcommand{\glfwdoctype}[1][0]{Users Guide} +\newcommand{\glfwapiver}[1][0]{2.7} + +% Common document settings and macros +\input{glfwdoc.sty} + +% PDF specific document settings +\hypersetup{pdftitle={GLFW Users Guide}} +\hypersetup{pdfauthor={Marcus Geelnard}} +\hypersetup{pdfkeywords={GLFW,OpenGL,guide,manual}} + + +%------------------------------------------------------------------------- +% Document body +%------------------------------------------------------------------------- + +\begin{document} + +\pagestyle{plain} + +% Title page +\glfwmaketitle + +% Summary, trademarks and table of contents +\pagenumbering{roman} +\setcounter{page}{1} + +%------------------------------------------------------------------------- +% Summary and Trademarks +%------------------------------------------------------------------------- +\chapter*{Summary} + +This document is a users guide for the \GLFW\ API that gives a practical +introduction to using \GLFW . For a more detailed description of the +\GLFW\ API you should refer to the \textit{GLFW Reference Manual}. +\vspace{10cm} + +\large +Trademarks + +\small +OpenGL and IRIX are registered trademarks of Silicon Graphics, Inc.\linebreak +Microsoft and Windows are registered trademarks of Microsoft Corporation.\linebreak +Mac OS is a registered trademark of Apple Computer, Inc.\linebreak +Linux is a registered trademark of Linus Torvalds.\linebreak +FreeBSD is a registered trademark of Wind River Systems, Inc.\linebreak +Solaris is a trademark of Sun Microsystems, Inc.\linebreak +UNIX is a registered trademark of The Open Group.\linebreak +X Window System is a trademark of The Open Group.\linebreak +POSIX is a trademark of IEEE.\linebreak +Truevision, TARGA and TGA are registered trademarks of Truevision, Inc.\linebreak +IBM is a registered trademark of IBM Corporation.\linebreak + +All other trademarks mentioned in this document are the property of their respective owners. +\normalsize + + +%------------------------------------------------------------------------- +% Table of contents +%------------------------------------------------------------------------- +\tableofcontents +\pagebreak + + +% Document chapters starts here... +\pagenumbering{arabic} +\setcounter{page}{1} + +\pagestyle{fancy} + + +%------------------------------------------------------------------------- +% Introduction +%------------------------------------------------------------------------- +\chapter{Introduction} +\thispagestyle{fancy} +\GLFW\ is a portable API (Application Program Interface) that handles +operating system specific tasks related to \OpenGL\ programming. While +\OpenGL\ in general is portable, easy to use and often results in tidy and +compact code, the operating system specific mechanisms that are required +to set up and manage an \OpenGL\ window are quite the opposite. \GLFW\ tries +to remedy this by providing the following functionality: + +\begin{itemize} +\item Opening and managing an \OpenGL\ window. +\item Keyboard, mouse and joystick input. +\item A high precision timer. +\item Support for querying and using \OpenGL\ extensions. +\end{itemize} +\vspace{18pt} + +All this functionality is implemented as a set of easy-to-use functions, +which makes it possible to write an \OpenGL\ application framework in just a +few lines of code. The \GLFW\ API is completely operating system and +platform independent, which makes it very simple to port \GLFW\ based \OpenGL\ +applications to a variety of platforms. + +Currently supported platforms are: +\begin{itemize} +\item Microsoft Windows\textsuperscript{\textregistered} 95/98/ME/NT/2000/XP/.NET Server. +\item Unix\textsuperscript{\textregistered} or Unix­-like systems running the +X Window System\texttrademark, e.g. Linux\textsuperscript{\textregistered}, +IRIX\textsuperscript{\textregistered}, FreeBSD\textsuperscript{\textregistered}, +Solaris\texttrademark, QNX\textsuperscript{\textregistered} and +Mac OS\textsuperscript{\textregistered} X. +\item Mac OS\textsuperscript{\textregistered} X (Carbon)\footnote{Support for joysticks missing at the time of writing.} +\end{itemize} + + +%------------------------------------------------------------------------- +% Getting Started +%------------------------------------------------------------------------- +\chapter{Getting Started} +\thispagestyle{fancy} +In this chapter you will learn how to write a simple \OpenGL\ application +using \GLFW . We start by initializing \GLFW , then we open a window and +read some user keyboard input. + + +%------------------------------------------------------------------------- +\section{Initializing GLFW} +Before using any of the \GLFW\ functions, it is necessary to call +\textbf{glfwInit}. It initializes internal working variables that are used +by other \GLFW\ functions. The C syntax is: + +\begin{lstlisting} +int glfwInit( void ) +\end{lstlisting} + +\textbf{glfwInit} returns GL\_TRUE if initialization succeeded, or +GL\_FALSE if it failed. + +When your application is done using \GLFW , typically at the very end of +the program, you should call \textbf{glfwTerminate}, which makes a clean +up and places \GLFW\ in a non-initialized state (i.e. it is necessary to +call \textbf{glfwInit} again before using any \GLFW\ functions). The C +syntax is: + +\begin{lstlisting} +void glfwTerminate( void ) +\end{lstlisting} + +Among other things, \textbf{glfwTerminate} closes the \OpenGL\ window +unless it was closed manually. + + +%------------------------------------------------------------------------- +\section{Opening An OpenGL Window} +Opening an \OpenGL\ window is done with the function +\textbf{glfwOpenWindow}. The function takes nine arguments, which are used +to describe the following properties of the window to open: + +\begin{itemize} +\item Window dimensions (width and height) in pixels. +\item Color and alpha buffer depth. +\item Depth buffer (Z-buffer) depth. +\item Stencil buffer depth. +\item Fullscreen or windowed mode. +\end{itemize} + +The C language syntax for \textbf{glfwOpenWindow} is: +\begin{lstlisting} +int glfwOpenWindow( int width, int height, + int redbits, int greenbits, int bluebits, + int alphabits, int depthbits, int stencilbits, + int mode ) +\end{lstlisting} + +\textbf{glfwOpenWindow} returns GL\_TRUE if the window was opened +correctly, or GL\_FALSE if \GLFW\ failed to open the window. + +\GLFW\ tries to open a window that best matches the requested parameters. +Some parameters may be omitted by setting them to zero, which will result +in \GLFW\ either using a default value, or the related functionality to be +disabled. For instance, if \textit{width} and \textit{height} are both +zero, \GLFW\ will use a window resolution of 640x480. If +\textit{depthbits} is zero, the opened window may not have a depth buffer. + +The \textit{mode} argument is used to specify if the window is to be a +s.c. fullscreen window, or a regular window. + +If \textit{mode} is GLFW\_FULLSCREEN, the window will cover the entire +screen and no window borders will be visible. If possible, the video mode +will be changed to the mode that closest matches the \textit{width}, +\textit{height}, \textit{redbits}, \textit{greenbits}, \textit{bluebits} +and \textit{alphabits} arguments. Furthermore, the mouse pointer will be +hidden, and screensavers are prohibited. This is usually the best mode for +games and demos. + +If \textit{mode} is GLFW\_WINDOW, the window will be opened as a normal +window on the desktop. The mouse pointer will not be hidden, and +screensavers are allowed to be activated. + +To close the window, you can either use \textbf{glfwTerminate}, as +described earlier, or you can use the more explicit approach by calling +\textbf{glfwCloseWindow}, which has the C syntax: + +\begin{lstlisting} +void glfwCloseWindow( void ) +\end{lstlisting} + + +%------------------------------------------------------------------------- +\section{Using Keyboard Input} +\GLFW\ provides several means for receiving user input, which will be +discussed in more detail in chapter \ref{par:inputhandling}. One of the +simplest ways of checking for keyboard input is to use the function +\textbf{glfwGetKey}: + +\begin{lstlisting} +int glfwGetKey( int key ) +\end{lstlisting} + +It queries the current status of individual keyboard keys. The argument +\textit{key} specifies which key to check, and it can be either an +uppercase printable ISO 8859-1 (Latin 1) character (e.g. `A', `3' or `.'), +or a special key identifier (see the \textit{GLFW Reference Manual} for a +list of special key identifiers). \textbf{glfwGetKey} returns GLFW\_PRESS +(or 1) if the key is currently held down, or GLFW\_RELEASE (or 0) if the +key is not being held down. For example: + +\begin{lstlisting} +A_pressed = glfwGetKey( 'A' ); +esc_pressed = glfwGetKey( GLFW_KEY_ESC ); +\end{lstlisting} + +In order for \textbf{glfwGetKey} to have any effect, you need to poll for +input events on a regular basis. This can be done in one of two ways: + +\begin{enumerate} +\item Implicitly by calling \textbf{glfwSwapBuffers} often. +\item Explicitly by calling \textbf{glfwPollEvents} often. +\end{enumerate} + +In general you do not have to care about this, since you will normally +call \textbf{glfwSwapBuffers} to swap front and back rendering buffers +every animation frame anyway. If, however, this is not the case, you +should call \textbf{glfwPollEvents} in the order of 10-100 times per +second in order for \GLFW\ to maintain an up to date input state. + + +%------------------------------------------------------------------------- +\section{Putting It Together: A Minimal GLFW Application} +Now that you know how to initialize \GLFW , open a window and poll for +keyboard input, let us exemplify this with a simple \OpenGL\ program. In +the following example some error-checking has been omitted for the sake of +brevity: + +\begin{lstlisting} +#include + +int main( void ) +{ + int running = GL_TRUE; + + // Initialize GLFW + glfwInit(); + + // Open an OpenGL window + if( !glfwOpenWindow( 300,300, 0,0,0,0,0,0, GLFW_WINDOW ) ) + { + glfwTerminate(); + return 0; + } + + // Main loop + while( running ) + { + // OpenGL rendering goes here... + glClear( GL_COLOR_BUFFER_BIT ); + + // Swap front and back rendering buffers + glfwSwapBuffers(); + + // Check if ESC key was pressed or window was closed + running = !glfwGetKey( GLFW_KEY_ESC ) && + glfwGetWindowParam( GLFW_OPENED ); + } + + // Close window and terminate GLFW + glfwTerminate(); + + // Exit program + return 0; +} +\end{lstlisting} + +The program opens a 300x300 window and runs in a loop until the escape key +is pressed, or the window was closed. All the \OpenGL\ ``rendering'' that +is done in this example is to clear the window. + + +%------------------------------------------------------------------------- +% Window Operations +%------------------------------------------------------------------------- +\chapter{Window Operations} +\thispagestyle{fancy} +In this chapter, you will learn more about window related \GLFW\ +functionality, including: setting and getting window properties, buffer +swap control and video mode querying. + + +%------------------------------------------------------------------------- +\section{Setting Window Properties} +In the previous chapter the \textbf{glfwOpenWindow} function was +described, which specifies the sizes of the color, alpha, depth and +stencil buffers. It is also possible to request an accumulator buffer, +auxiliary buffers and stereo rendering by using the +\textbf{glfwOpenWindowHint} function: + +\begin{lstlisting} +void glfwOpenWindowHint( int target, int hint ) +\end{lstlisting} + +The \textit{target} argument can be one of the constants listed in table~ +\ref{tab:winhints}, and \textit{hint} is the value to assign to the +specified target. + +%------------------------------------------------------------------------- +\begin{table}[p] +\begin{center} +\begin{tabular}{|l|l|p{7.0cm}|} \hline \raggedright +\textbf{Name} & \textbf{Default} & \textbf{Description} \\ \hline +GLFW\_REFRESH\_RATE & 0 & Vertical monitor refresh rate in Hz (only used for fullscreen windows). Zero means system default.\\ \hline +GLFW\_ACCUM\_RED\_BITS & 0 & Number of bits for the red channel of the accumulator buffer.\\ \hline +GLFW\_ACCUM\_GREEN\_BITS & 0 & Number of bits for the green channel of the accumulator buffer.\\ \hline +GLFW\_ACCUM\_BLUE\_BITS & 0 & Number of bits for the blue channel of the accumulator buffer.\\ \hline +GLFW\_ACCUM\_ALPHA\_BITS & 0 & Number of bits for the alpha channel of the accumulator buffer.\\ \hline +GLFW\_AUX\_BUFFERS & 0 & Number of auxiliary buffers.\\ \hline +GLFW\_STEREO & GL\_FALSE & Specify if stereo rendering should be supported (can be GL\_TRUE or GL\_FALSE).\\ \hline +GLFW\_WINDOW\_NO\_RESIZE & GL\_FALSE & Specify whether the window can be resized (not used for fullscreen windows).\\ \hline +GLFW\_FSAA\_SAMPLES & 0 & Number of samples to use for the multisampling buffer. Zero disables multisampling.\\ \hline +GLFW\_OPENGL\_VERSION\_MAJOR & 0 & Major number of the desired OpenGL version. + The default requests the highest OpenGL version equal to or lower than 2.1.\\ \hline +GLFW\_OPENGL\_VERSION\_MINOR & 0 & Minor number of the desired OpenGL version. + The default requests the highest OpenGL version equal to or lower than 2.1.\\ \hline +GLFW\_OPENGL\_FORWARD\_COMPAT & GL\_FALSE & Specify whether the OpenGL context should be forward compatible (i.e. disallow legacy functionality). + This hint is ignored for OpenGL version 2.1 and below.\\ \hline +\end{tabular} +\end{center} +\caption{Targets for \textbf{glfwOpenWindowHint}} +\label{tab:winhints} +\end{table} +%------------------------------------------------------------------------- + +For a hint to have any effect, the \textbf{glfwOpenWindowHint} function +must be called before opening the window with the \textbf{glfwOpenWindow} +function. + +To request an accumulator buffer, set the GLFW\_ACCUM\_x\_BITS targets to +values greater than zero (usually eight or sixteen bits per component). +To request auxiliary buffers, set the GLFW\_AUX\_BUFFERS target to a value +greater than zero. To request a stereo rendering capable window, set the +GLFW\_STEREO target to GL\_TRUE. + +If you want to enable fullscreen antialiasing, set the GLFW\_FSAA\_SAMPLES +target to a value greater than zero. If the windowing system is unable to +fulfil the request, \GLFW\ will degrade gracefully and disable FSAA if necessary. + +The GLFW\_REFRESH\_RATE target should be used with caution, since it may +result in suboptimal operation, or even a blank or damaged screen. + +If you want to create a context with OpenGL version 3.0 or above you have to +set the GLFW\_OPENGL\_VERSION\_MAJOR and GLFW\_OPENGL\_VERSION\_MINOR hints +accordingly. If you don't do this, the highest OpenGL version available for a +context is 2.1 or lower. + +Besides the parameters that are given with the \textbf{glfwOpenWindow} and +\textbf{glfwOpenWindowHint} functions, a few more properties of a window +can be changed after the window has been opened, namely the window title, +window size, and window position. + +To change the window title of an open window, use the +\textbf{glfwSetWindowTitle} function: + +\begin{lstlisting} +void glfwSetWindowTitle( const char *title ) +\end{lstlisting} + +\textit{title} is a null terminated ISO~8859-1 (8-bit Latin~1) string that +will be used as the window title. It will also be used as the application +name (for instance in the application list when using \texttt{ALT+TAB} +under Windows, or as the icon name when the window is iconified under +the X Window System). The default window name is ``GLFW Window'', which +will be used unless \textbf{glfwSetWindowTitle} is called after the window +has been opened. + +To change the size of a window, call \textbf{glfwSetWindowSize}: + +\begin{lstlisting} +void glfwSetWindowSize( int width, int height ) +\end{lstlisting} + +Where \textit{width} and \textit{height} are the new dimensions of the +window. + +To change the position of a window, call \textbf{glfwSetWindowPos}: + +\begin{lstlisting} +void glfwSetWindowPos( int x, int y ) +\end{lstlisting} + +Where \textit{x} and \textit{y} are the new desktop coordinates of the +window. This function does not have any effect when in fullscreen mode. + + +%------------------------------------------------------------------------- +\section{Getting Window Properties} +When opening a window, the opened window will not necessarily have the +requested properties, so you should always check the parameters that your +application relies on (e.g. number of stencil bits) using +\textbf{glfwGetWindowParam}, which has the C syntax: + +\begin{lstlisting} +int glfwGetWindowParam( int param ) +\end{lstlisting} + +The argument \textit{param} can be one of the tokens listed in table +\ref{tab:winparams}, and the return value is an integer holding the +requested value. + +%------------------------------------------------------------------------- +\begin{table}[p] +\begin{center} +\begin{tabular}{|l|p{9.5cm}|} \hline \raggedright +\textbf{Name} & \textbf{Description} \\ \hline +GLFW\_OPENED & GL\_TRUE if window is opened, else GL\_FALSE.\\ \hline +GLFW\_ACTIVE & GL\_TRUE if window has focus, else GL\_FALSE.\\ \hline +GLFW\_ICONIFIED & GL\_TRUE if window is iconified, else GL\_FALSE.\\ \hline +GLFW\_ACCELERATED & GL\_TRUE if window is hardware accelerated, else GL\_FALSE.\\ \hline +GLFW\_RED\_BITS & Number of bits for the red color component.\\ \hline +GLFW\_GREEN\_BITS & Number of bits for the green color component.\\ \hline +GLFW\_BLUE\_BITS & Number of bits for the blue color component.\\ \hline +GLFW\_ALPHA\_BITS & Number of bits for the alpha buffer.\\ \hline +GLFW\_DEPTH\_BITS & Number of bits for the depth buffer.\\ \hline +GLFW\_STENCIL\_BITS & Number of bits for the stencil buffer.\\ \hline +GLFW\_REFRESH\_RATE & Vertical monitor refresh rate in Hz. Zero indicates an unknown or a default refresh rate.\\ \hline +GLFW\_ACCUM\_RED\_BITS & Number of bits for the red channel of the accumulator buffer.\\ \hline +GLFW\_ACCUM\_GREEN\_BITS & Number of bits for the green channel of the accumulator buffer.\\ \hline +GLFW\_ACCUM\_BLUE\_BITS & Number of bits for the blue channel of the accumulator buffer.\\ \hline +GLFW\_ACCUM\_ALPHA\_BITS & Number of bits for the alpha channel of the accumulator buffer.\\ \hline +GLFW\_AUX\_BUFFERS & Number of auxiliary buffers.\\ \hline +GLFW\_STEREO & GL\_TRUE if stereo rendering is supported, else GL\_FALSE.\\ \hline +GLFW\_WINDOW\_NO\_RESIZE & GL\_TRUE if the window cannot be resized, else GL\_FALSE.\\ \hline +GLFW\_FSAA\_SAMPLES & Number of multisampling buffer samples. Zero indicated multisampling is disabled.\\ \hline +GLFW\_OPENGL\_VERSION\_MAJOR & Major number of the desired OpenGL version.\\ \hline +GLFW\_OPENGL\_VERSION\_MINOR & Minor number of the desired OpenGL version.\\ \hline +GLFW\_OPENGL\_FORWARD\_COMPAT & GL\_TRUE if the OpenGL context is forward compatible (i.e. disallows legacy functionality), else GL\_FALSE. +This is always GL\_FALSE for OpenGL version 2.1 and below.\\ \hline +\end{tabular} +\end{center} +\caption{Window parameters for \textbf{glfwGetWindowParam}} +\label{tab:winparams} +\end{table} +%------------------------------------------------------------------------- + +Another useful function is \textbf{glfwSetWindowSizeCallback}, which +specifies a user function that will be called every time the window size +has changed. The C syntax is: + +\begin{lstlisting} +void glfwSetWindowSizeCallback( GLFWwindowsizefun cbfun ) +\end{lstlisting} + +The user function \textit{fun} should be of the type: + +\begin{lstlisting} +void GLFWCALL fun( int width, int height ) +\end{lstlisting} + +The first argument passed to the user function is the width of the window, +and the second argument is the height of the window. Here is an example +of how to use a window size callback function: + +\begin{lstlisting} +int WinWidth, WinHeight; + +void GLFWCALL WindowResize( int width, int height ) +{ + WinWidth = width; + WinHeight = height; +} + +int main( void ) +{ + ... + glfwSetWindowSizeCallback( WindowResize ); + ... +} +\end{lstlisting} + +Using a callback function for getting the window size is mostly useful for +windowed applications, since the window size may be changed at any time by +the user. It can also be used to determine the actual fullscreen +resolution. + +An alternative to using a callback function for getting the window size, +is to use the function \textbf{glfwGetWindowSize}: + +\begin{lstlisting} +void glfwGetWindowSize( int *width, int *height ) +\end{lstlisting} + +The \textit{width} and \textit{height} arguments are filled out with the +current window dimensions. + + +%------------------------------------------------------------------------- +\section{Buffer Swapping} +\GLFW\ windows are always double buffered. That means that you have two +rendering buffers; a front buffer and a back buffer. The front buffer is +the buffer that is being displayed, and the back buffer is not displayed. +\OpenGL\ lets you select which of these two buffers you want to render to +(with the \textbf{glDrawBuffer} command), but the default (and preferred) +rendering buffer is the back buffer. This way you will avoid flickering +and artifacts caused by graphics being only partly drawn at the same time +as the video raster beam is displaying the graphics on the monitor. + +When an entire frame has been rendered to the back buffer, it is time to +swap the back and the front buffers in order to display the rendered +frame, and begin rendering a new frame. This is done with the command +\textbf{glfwSwapBuffers}. The C syntax is: + +\begin{lstlisting} +void glfwSwapBuffers( void ) +\end{lstlisting} + +Besides swapping the front and back rendering buffers, +\textbf{glfwSwapBuffers} also calls \textbf{glfwPollEvents}\footnote{This +behavior can be disabled by calling \textbf{glfwDisable} with the argument +GLFW\_AUTO\_POLL\_EVENTS.}. This is to ensure frequent polling of events, +such as keyboard and mouse input, and window reshaping events. + +Sometimes it can be useful to select when the buffer swap will occur. With +the function \textbf{glfwSwapInterval} it is possible to select the +minimum number of vertical retraces the video raster line should do before +swapping the buffers: + +\begin{lstlisting} +void glfwSwapInterval( int interval ) +\end{lstlisting} + +If \textit{interval} is zero, the swap will take place immediately when +\textbf{glfwSwapBuffers} is called, without waiting for a vertical retrace +(also known as ``vsync off''). Otherwise at least \textit{interval} +retraces will pass between each buffer swap (also known as ``vsync on''). +Using a swap interval of zero can be useful for benchmarking purposes, +when it is not desirable to measure the time it takes to wait for the +vertical retrace. However, a swap interval of 1 generally gives better +visual quality. + +It should be noted that not all \OpenGL\ implementations and hardware +support this function, in which case \textbf{glfwSwapInterval} will have +no effect. Sometimes it is only possible to affect the swap interval +through driver settings (e.g. the display settings under Windows, or as an +environment variable setting under Unix). + + +%------------------------------------------------------------------------- +\section{Querying Video Modes} +Although \GLFW\ generally does a good job at selecting a suitable video +mode for you when you open a fullscreen window, it is sometimes useful to +know exactly which modes are available on a certain system. For example, +you may want to present the user with a list of video modes to select +from. To get a list of available video modes, you can use the function +\textbf{glfwGetVideoModes}: + +\begin{lstlisting} +int glfwGetVideoModes( GLFWvidmode *list, int maxcount ) +\end{lstlisting} + +The argument \textit{list} is a vector of GLFWvidmode structures, and +\textit{maxcount} is the maximum number of video modes that your vector +can hold. \textbf{glfwGetVideoModes} will return the actual number of +video modes detected on the system. + +The GLFWvidmode structure looks like this: + +\begin{lstlisting} +typedef struct { + int Width, Height; // Video resolution + int RedBits; // Red bits per pixel + int GreenBits; // Green bits per pixel + int BlueBits; // Blue bits per pixel +} GLFWvidmode; +\end{lstlisting} + +Here is an example of retrieving all available video modes: + +\begin{lstlisting} +int nummodes; +GLFWvidmode list[ 200 ]; +nummodes = glfwGetVideoModes( list, 200 ); +\end{lstlisting} + +The returned list is sorted, first by color depth ($RedBits + GreenBits + +BlueBits$), and then by resolution ($Width\times Height$), with the +lowest resolution, fewest bits per pixel mode first. + +To get the desktop video mode, use the function +\textbf{glfwGetDesktopMode}: + +\begin{lstlisting} +void glfwGetDesktopMode( GLFWvidmode *mode ) +\end{lstlisting} + +The function returns the resolution and color depth of the user desktop in +the mode structure. Note that the user desktop mode is independent of the +current video mode if a \GLFW\ fullscreen window has been opened. + + +%------------------------------------------------------------------------- +% Input Handling +%------------------------------------------------------------------------- +\chapter{Input Handling} +\label{par:inputhandling} +\thispagestyle{fancy} +In this chapter you will learn how to use keyboard, mouse and joystick +input, using either polling or callback functions. + + +%------------------------------------------------------------------------- +\section{Event Polling} +The first thing to know about input handling in \GLFW\ is that all +keyboard and mouse input is collected by checking for input events. This +has do be done manually by calling either \textbf{glfwPollEvents} or +\textbf{glfwSwapBuffers} (which implicitly calls \textbf{glfwPollEvents} +for you). Normally this does not have to be a concern, since +\textbf{glfwSwapBuffers} is called every frame, which should be often +enough (about 10-100 times per second for a normal \OpenGL\ application). +One exception is when rendering is paused, and then the program waits for +input to begin animation again. In this case \textbf{glfwPollEvents} has +to be called repeatedly until any new input events arrive. + +If it is not desirable that \textbf{glfwPollEvents is} called implicitly +from \textbf{glfwSwapBuffers}, call \textbf{glfwDisable} with the argument +GLFW\_AUTO\_POLL\_EVENTS. + +Note that event polling is not needed for joystick input, since all +relevant joystick state is gathered every time a joystick function is +called. + + +%------------------------------------------------------------------------- +\section{Keyboard Input} +\GLFW\ gives three options for getting keyboard input: + +\begin{itemize} +\item Manually polling the state of individual keys. +\item Automatically receive new key state for any key, using a callback + function. +\item Automatically receive characters, using a callback function. +\end{itemize} + +Depending on what the keyboard input will be used for, either of the +methods may be more suitable. The main difference between the two last +options is that while characters are affected by modifier keys (such as +shift), key state is independent of any modifier keys. Also, special keys +(such as function keys, cursor keys and modifier keys) are not reported to +the character callback function. + +%------------------------------------------------------------------------- +\subsection{Key state} +To check if a key is held down or not at any given moment, use the +function \textbf{glfwGetKey}: + +\begin{lstlisting} +int glfwGetKey( int key ) +\end{lstlisting} + +It queries the current status of individual keyboard keys. The argument +\textit{key} specifies which key to check, and it can be either an +uppercase ISO~8859-1 character, or a special key identifier. +\textbf{glfwGetKey} returns GLFW\_PRESS (or 1) if the key is currently +held down, or GLFW\_RELEASE (or 0) if the key is not being held down. + +In most situations, it may be useful to know if a key has been pressed and +released between two calls to \textbf{glfwGetKey} (especially if the +animation is fairly slow, which may allow the user to press and release a +key between two calls to \textbf{glfwGetKey}). This can be accomplished by +enabling sticky keys, which is done by calling \textbf{glfwEnable} with +the argument GLFW\_STICKY\_KEYS, as in the following example: + +\begin{lstlisting} +glfwEnable( GLFW_STICKY_KEYS ); +\end{lstlisting} + +When sticky keys are enabled, a key will not be released until it is +checked with \textbf{glfwGetKey}. To disable sticky keys, call +\textbf{glfwDisable} witht the argument GLFW\_STICKY\_KEYS. Then all keys +that are not currently held down will be released, and future key releases +will take place immediately when the user releases the key, without +waiting for \textbf{glfwGetKey} to check the key. By default sticky keys +are disabled. + +Sticky keys are often very useful and should be used in most cases where +\textbf{glfwGetKey} is used. There is however a danger involved with +enabling sticky keys, and that is that keys that are pressed by the user +but are not checked with \textbf{glfwGetKey}, may remain ``pressed'' for a +very long time. A typical situation where this may be dangerous is in a +program that consists of two or more sections (e.g. a menu section and a +game section). If the first section enables sticky keys but does not check +for keys which the second section checks for, there is a potential of +recording many key presses in the first section that will be detected in +the second section. To avoid this problem, always disable sticky keys +before leaving a section of a program. + +An alternative to using \textbf{glfwGetKey} is to register a keyboard +input callback function with \textbf{glfwSetKeyCallback}: + +\begin{lstlisting} +void glfwSetKeyCallback( GLFWkeyfun cbfun ) +\end{lstlisting} + +The argument \textit{fun} is a pointer to a callback function. The +callback function shall take two integer arguments. The first is the key +identifier, and the second is the new key state, which can be GLFW\_PRESS +or GLFW\_RELEASE. To unregister a callback function, call +\textbf{glfwSetKeyCallback} with \textit{fun} = NULL. + +A callback function can be useful in some situations. For instance it can +replace multiple \textbf{glfwGetKey} calls with a switch/case statement. + +%------------------------------------------------------------------------- +\subsection{Character input} +If the keyboard is to be used as a text input device (e.g. in a user +dialog) rather than as a set of independent buttons, a character callback +function is more suitable. To register a character callback function, use +\textbf{glfwSetCharCallback}: + +\begin{lstlisting} +void glfwSetCharCallback( GLFWcharfun cbfun ) +\end{lstlisting} + +The argument \textit{fun} is a pointer to a callback function. The +callback function shall take two integer arguments. The first is a Unicode +character code, and the second is GLFW\_PRESS if the key that generated +the character was pressed, or GLFW\_RELEASE if it was released. To +unregister a callback function, call \textbf{glfwSetCharCallback} with +\textit{fun} = NULL. + +The Unicode character set is an international standard for encoding +characters. It is much more comprehensive than seven or eight bit +character sets (e.g. US-ASCII and Latin~1), and includes characters for +most written languages in the world. It should be noted that Unicode +character codes 0 to 255 are the same as for ISO~8859-1 (Latin~1), so as +long as a proper range check is performed on the Unicode character code, +it can be used just as an eight bit Latin~1 character code (which can be +useful if full Unicode support is not possible). + + +%------------------------------------------------------------------------- +\subsection{Key repeat} +By default, \GLFW\ does not report key repeats when a key is held down. +To activate key repeat, call \textbf{glfwEnable} with the argument +GLFW\_KEY\_REPEAT: + +\begin{lstlisting} +glfwEnable( GLFW_KEY_REPEAT ); +\end{lstlisting} + +This will let a registered key or character callback function receive key +repeat events when a key is held down. + + +%------------------------------------------------------------------------- +\subsection{Special system keys} +On most systems there are some special system keys that are normally not +intercepted by an application. For instance, under Windows it is possible +to switch programs by pressing \texttt{ALT+TAB}, which brings up a list of +running programs to select from. In certain situations it can be desirable +to prevent such special system keys from interfering with the program. +With \GLFW\ it is possible to do by calling \textbf{glfwDisable} with the +argument GLFW\_SYSTEM\_KEYS: + +\begin{lstlisting} +glfwDisable( GLFW_SYSTEM_KEYS ); +\end{lstlisting} + +By doing so, most system keys will have no effect and will not interfere +with your program. System keys can be re-enabled by calling +\textbf{glfwEnable} with the argument GLFW\_SYSTEM\_KEYS. By default, +system keys are enabled. + + +%------------------------------------------------------------------------- +\section{Mouse Input} +Just like for keyboard input, mouse input can be realized with either +polling or callback functions. + + +%------------------------------------------------------------------------- +\subsection{Mouse position} +To read the mouse position, you can use the function +\textbf{glfwGetMousePos}: + +\begin{lstlisting} +void glfwGetMousePos( int *x, int *y ) +\end{lstlisting} + +The arguments \textit{x} and \textit{y} point to integer variables that +will be updated with the current absolute mouse position. An alternative +is to use a callback function instead, which can be set with +\textbf{glfwSetMousePosCallback}: + +\begin{lstlisting} +void glfwSetMousePosCallback( GLFWmouseposfun cbfun ) +\end{lstlisting} + +The function that \textit{fun} points to will be called every time the +mouse position changes. The first argument to the callback function is +the mouse x position, and the second argument is the mouse y position. + + +%------------------------------------------------------------------------- +\subsection{Mouse buttons} +To query the state of a mouse button, call \textbf{glfwGetMouseButton}: + +\begin{lstlisting} +int glfwGetMouseButton( int button ) +\end{lstlisting} + +The argument \textit{button} can be one of the following mouse button +identifiers: GLFW\_MOUSE\_BUTTON\_LEFT, GLFW\_MOUSE\_BUTTON\_RIGHT or +GLFW\_MOUSE\_BUTTON\_MIDDLE. \textbf{glfwGetMouseButton} will return +GLFW\_PRESS (which is a non-zero value) if the corresponding mouse +button is held down, otherwise it will return GLFW\_RELEASE (which is +equal to zero). + +Just as it is possible to make keys ``sticky'', it is also possible to +make mouse buttons appear as held down until the button is checked for +with \textbf{glfwGetMouseButton}. To enable sticky mouse buttons, call +\textbf{glfwEnable} with the argument GLFW\_STICKY\_MOUSE\_BUTTONS. + +When sticky mouse buttons are enabled, a mouse button will not be released +until it is checked with \textbf{glfwGetMouseButton}. To disable sticky +mouse buttons, call \textbf{glfwDisable} with the argument +GLFW\_STICKY\_MOUSE\_BUTTONS. Then all mouse buttons that are not +currently held down will be released, and future mouse button releases +will take place immediately when the user releases the mouse button, +without waiting for \textbf{glfwGetMouseButton} to check for the mouse +button. By default sticky mouse buttons are disabled. + +There is also a callback function for mouse button activities, which can +be set with \textbf{glfwSetMouseButtonCallback}: + +\begin{lstlisting} +void glfwSetMouseButtonCallback( GLFWmousebuttonfun fun ) +\end{lstlisting} + +The argument \textit{fun} specifies a function that will be called +whenever a mouse button is pressed or released, or NULL to unregister a +callback function. The first argument to the callback function is a mouse +button identifier, and the second is either GLFW\_PRESS or GLFW\_RELEASE, +depending on the new state of the corresponding mouse button. + + +%------------------------------------------------------------------------- +\subsection{Mouse wheel} +Some mice have a mouse wheel, which can be thought of as a third mouse +axis. To get the position of the mouse wheel, call +\textbf{glfwGetMouseWheel}: + +\begin{lstlisting} +int glfwGetMouseWheel( void ) +\end{lstlisting} + +The function returns an integer that represents the position of the mouse +wheel. When the user turns the wheel, the wheel position will increase or +decrease. + +It is also possible to register a callback function for mouse wheel events +with the \textbf{glfwSetMouseWheelCallback} function: + +\begin{lstlisting} +void glfwSetMouseWheelCallback( GLFWmousewheelfun fun ) +\end{lstlisting} + +The argument \textit{fun} specifies a function that will be called +whenever the mouse wheel is moved, or NULL to unregister a callback +function. The argument to the callback function is the position of the +mouse wheel. + + +%------------------------------------------------------------------------- +\subsection{Hiding the mouse cursor} +It is possible to hide the mouse cursor with the function call: + +\begin{lstlisting} +glfwDisable( GLFW_MOUSE_CURSOR ); +\end{lstlisting} + +Hiding the mouse cursor has three effects: + +\begin{enumerate} +\item The cursor becomes invisible. +\item The cursor is guaranteed to be confined to the window. +\item Mouse coordinates are not limited to the window size. +\end{enumerate} + +To show the mouse cursor again, call \textbf{glfwEnable} with the +argument GLFW\_MOUSE\_CURSOR: + +\begin{lstlisting} +glfwEnable( GLFW_MOUSE_CURSOR ); +\end{lstlisting} + +By default the mouse cursor is hidden if a window is opened in fullscreen +mode, otherwise it is not hidden. + + +%------------------------------------------------------------------------- +\section{Joystick Input} +\GLFW\ has support for up to sixteen joysticks, and an infinite\footnote{% +There are of course actual limitations posed by the underlying hardware, +drivers and operation system.} number of axes and buttons per joystick. +Unlike keyboard and mouse input, joystick input does not need an opened +window, and \textbf{glfwPollEvents} or \textbf{glfwSwapBuffers} does not +have to be called in order for joystick state to be updated. + + +%------------------------------------------------------------------------- +\subsection{Joystick capabilities} +First, it is often necessary to determine if a joystick is connected, and +what its capabilities are. To get this information the function +\textbf{glfwGetJoystickParam} can be used: + +\begin{lstlisting} +int glfwGetJoystickParam( int joy, int param ) +\end{lstlisting} + +The \textit{joy} argument specifies which joystick to retrieve the +parameter from, and it should be GLFW\_JOYSTICK\_\textit{n}, where +\textit{n} is in the range 1 to 16. The \textit{param} argument specifies +which parameter to retrieve. To determine if a joystick is connected, +\textit{param} should be GLFW\_PRESENT, which will cause the function to +return GL\_TRUE if the joystick is connected, or GL\_FALSE if it is not. +To determine the number of axes or buttons that are supported by the +joystick, \textit{param} should be GLFW\_AXES or GLFW\_BUTTONS, +respectively. + + +%------------------------------------------------------------------------- +\subsection{Joystick position} +To get the current axis positions of the joystick, the +\textbf{glfwGetJoystickPos} is used: + +\begin{lstlisting} +int glfwGetJoystickPos( int joy, float *pos, int numaxes ) +\end{lstlisting} + +As with \textbf{glfwGetJoystickParam}, the \textit{joy} argument +specifies which joystick to retrieve information from. The +\textit{numaxes} argument specifies how many axes to return, and the +\textit{pos} argument specifies an array in which all the axis positions +are stored. The function returns the actual number of axes that were +returned, which could be less than \textit{numaxes} if the joystick does +not support all the requested axes, or if the joystick is not connected. + +For instance, to get the position of the first two axes (the X and Y axes) +of joystick 1, the following code can be used: + +\begin{lstlisting} +float position[ 2 ]; + +glfwGetJoystickPos( GLFW_JOYSTICK_1, position, 2 ); +\end{lstlisting} + +After this call, the first element of the \textit{position} array will +hold the X axis position of the joystick, and the second element will hold +the Y axis position. In this example we do not use the information about +how many axes were really returned. + +The position of an axis can be in the range -1.0 to 1.0, where positive +values represent right, forward or up directions, while negative values +represent left, back or down directions. If a requested axis is not +supported by the joystick, the corresponding array element will be set +to zero. The same goes for the situation when the joystick is not +connected (all axes are treated as unsupported). + + +%------------------------------------------------------------------------- +\subsection{Joystick buttons} +A function similar to the \textbf{glfwGetJoystickPos} function is +available for querying the state of joystick buttons, namely the +\textbf{glfwGetJoystickButtons} function: + +\begin{lstlisting} +int glfwGetJoystickButtons( int joy, unsigned char *buttons, + int numbuttons ) +\end{lstlisting} + +The function works just like the \textbf{glfwGetJoystickAxis} function, +except that it returns the state of joystick buttons instead of axis +positions. Each button in the array specified by the \textit{buttons} +argument can be either GLFW\_PRESS or GLFW\_RELEASE, telling if the +corresponding button is currently held down or not. Unsupported buttons +will have the value GLFW\_RELEASE. + + +%------------------------------------------------------------------------- +% Timing +%------------------------------------------------------------------------- +\chapter{Timing} +\thispagestyle{fancy} + +%------------------------------------------------------------------------- +\section{High Resolution Timer} +In most applications, it is useful to know exactly how much time has +passed between point $A$ and point $B$ in a program. A typical situation +is in a game, where you need to know how much time has passed between two +rendered frames in order to calculate the correct movement and physics +etc. Another example is when you want to benchmark a certain piece of +code. + +\GLFW\ provides a high-resolution timer, which reports a double precision +floating point value representing the number of seconds that have passed +since \textbf{glfwInit} was called. The timer is accessed with the +function \textbf{glfwGetTime}: + +\begin{lstlisting} +double glfwGetTime( void ) +\end{lstlisting} + +The precision of the timer depends on which computer and operating +system you are running, but it is almost guaranteed to be better than +$10~ms$, and in most cases it is much better than $1~ms$ (on a modern PC +you can get resolutions in the order of $1~ns$). + +It is possible to set the value of the high precision timer using the +\textbf{glfwSetTime} function: + +\begin{lstlisting} +void glfwSetTime( double time ) +\end{lstlisting} + +The argument \textit{time} is the time, in seconds, that the timer should +be set to. + + +%------------------------------------------------------------------------- +% OpenGL Extension Support +%------------------------------------------------------------------------- +\chapter{OpenGL Extension Support} +\thispagestyle{fancy} +One of the benefits of \OpenGL\ is that it is extensible. Independent +hardware vendors (IHVs) may include functionality in their \OpenGL\ +implementations that exceed that of the \OpenGL\ standard. + +An extension is defined by: + +\begin{enumerate} +\item An extension name (e.g. GL\_ARB\_multitexture). +\item New OpenGL tokens (e.g. GL\_TEXTURE1\_ARB). +\item New OpenGL functions (e.g. \textbf{glActiveTextureARB}). +\end{enumerate} + +A list of official extensions, together with their definitions, can be +found at the \textit{OpenGL Extension Registry} +(\url{http://oss.sgi.com/projects/ogl-sample/registry/}). + +To use a certain extension, the following steps must be performed: + +\begin{enumerate} +\item A compile time check for the support of the extension. +\item A run time check for the support of the extension. +\item Fetch function pointers for the extended \OpenGL\ functions (done at + run time). +\end{enumerate} + +How this is done using \GLFW\ is described in the following sections. +Please note that this chapter covers some advanced topics, and is quite +specific to the C programming language. + + +%------------------------------------------------------------------------- +\section{Compile Time Check} +The compile time check is necessary to perform in order to know if the +compiler include files have defined the necessary tokens. It is very easy +to do. The include file \texttt{GL/gl.h} will define a constant with the +same name as the extension, if all the extension tokens are defined. Here +is an example of how to check for the extension GL\_ARB\_multitexture: + +\begin{lstlisting} +#ifdef GL_ARB_multitexture + // Extension is supported by the include files +#else + // Extension is not supported by the include files + // Update your file! +#endif +\end{lstlisting} + + +%------------------------------------------------------------------------- +\section{Runtime Check} +Even if the compiler include files have defined all the necessary tokens, +the target system may not support the extension (perhaps it has a +different graphic card with a different \OpenGL\ implementation, or it has +an older driver). That is why it is necessary to do a run time check for +the extension support as well. This is done with the \GLFW\ function +\textbf{glfwExtensionSupported}, which has the C syntax: + +\begin{lstlisting} +int glfwExtensionSupported( const char *extension ) +\end{lstlisting} + +The argument \textit{extension} is a null terminated ISO~8859-1 string +with the extension name. \textbf{glfwExtensionSupported} returns GL\_TRUE +if the extension is supported, otherwise it returns GL\_FALSE. + +Let us extend the previous example of checking for support of the +extension GL\_ARB\_multitexture. This time we add a run time check, and a +variable which we set to GL\_TRUE if the extension is supported, or +GL\_FALSE if it is not supported. + +\begin{lstlisting} +int multitexture_supported; + +#ifdef GL_ARB_multitexture + // Check if extension is supported at run time + multitexture_supported = + glfwExtensionSupported( "GL_ARB_multitexture" ); +#else + // Extension is not supported by the include files + // Update your file! + multitexture_supported = GL_FALSE; +#endif +\end{lstlisting} + +Now it is easy to check for the extension within the program, simply do: + +\begin{lstlisting} + if( multitexture_supported ) + { + // Use multi texturing + } + else + { + // Use some other solution (or fail) + } +\end{lstlisting} + + +%------------------------------------------------------------------------- +\section{Fetching Function Pointers} +Some extensions (not all) require the use of new \OpenGL\ functions, which +are not necessarily defined by your link libraries. Thus it is necessary +to get the function pointers dynamically at run time. This is done with +the \GLFW\ function \textbf{glfwGetProcAddress}: + +\begin{lstlisting} +void * glfwGetProcAddress( const char *procname ) +\end{lstlisting} + +The argument \textit{procname} is a null terminated ISO~8859-1 string +holding the name of the \OpenGL\ function. \textbf{glfwGetProcAddress} +returns the address to the function if the function is available, +otherwise NULL is returned. + +Obviously, fetching the function pointer is trivial. For instance, if we +want to obtain the pointer to \textbf{glActiveTextureARB}, we simply call: + +\begin{lstlisting} +glActiveTextureARB = glfwGetProcAddress( "glActiveTextureARB" ); +\end{lstlisting} + +However, there are many possible naming and type definition conflicts +involved with such an operation, which may result in compiler warnings or +errors. My proposed solution is the following: + +\begin{itemize} +\item Do not use the function name for the variable name. Use something + similar (perhaps with a prefix or suffix), and then use + \texttt{\#define} to map the function name to your variable. +\item The standard type definition naming convention for function pointers + is \texttt{PFN\textit{xxxx}PROC}, where \texttt{\textit{xxxx}} is + the uppercase version of the function name (e.g. + \texttt{PFNGLACTIVETEXTUREARBPROC}). Either make sure that a + compatible \texttt{gl.h} and/or \texttt{glext.h} file is used by + your compiler and rely on it to do the type definitions for you, or + use a custom type definition naming convention (e.g. + \texttt{\textit{xxxx}\_T} or something) and do the type definitions + yourself. +\end{itemize} + +Here is an example of how to do it (here we use our own function pointer +type defintion): + +\begin{lstlisting} +// Type definition of the function pointer +typedef void (APIENTRY * GLACTIVETEXTUREARB_T) (GLenum texture); + +// Function pointer +GLACTIVETEXTUREARB_T _ActiveTextureARB; +#define glActiveTextureARB _ActiveTextureARB + +// Extension availability flag +int multitexture_supported; + +#ifdef GL_ARB_multitexture + // Check if extension is supported at run time + if( glfwExtensionSupported( "GL_ARB_multitexture" ) ) + { + // Get the function pointer + glActiveTextureARB = (GLACTIVETEXTUREARB_T) + glfwGetProcAddress( "glActiveTextureARB" ); + + multitexture_supported = GL_TRUE; + } + else + { + multitexture_supported = GL_FALSE; + } +#else + // Extension is not supported by the include files + multitexture_supported = GL_FALSE; +#endif +\end{lstlisting} + +Please note that the code example is not 100\% complete. First of all, +the GL\_ARB\_multitexture extension defines many more functions than the +single function that the code example defines. Secondly, checking if an +extension is supported using \textbf{glfwExtensionSupported} is not enough +to ensure that the corresponding functions will be valid. You also need to +check if the function pointers returned by \textbf{glfwGetProcAddress} are +non-NULL values. + + +%------------------------------------------------------------------------- +\subsection{Function pointer type definitions} +To make a function pointer type definition, you need to know the function +prototype. This can often be found in the extension definitions (e.g. at +the \textit{OpenGL Extension Registry}). All the functions that are +defined for an extension are listed with their C prototype definitions +under the section \textit{New Procedures and Functions} in the extension +definition. + +For instance, if we look at the definition of the +GL\_ARB\_texture\_compression extension, we find a list of new functions. +One of the functions looks like this: + +\begin{lstlisting} +void GetCompressedTexImageARB(enum target, int lod, void *img); +\end{lstlisting} + +Like in most official \OpenGL\ documentation, all the \texttt{GL} and +\texttt{gl} prefixes have been left out. In other words, the real function +prototype would look like this: + +\begin{lstlisting} +void glGetCompressedTexImageARB(GLenum target, GLint lod, void *img); +\end{lstlisting} + +All we have to do to turn this prototype definition into a function +pointer type definition, is to replace the function name with +\texttt{(APIENTRY * \textit{xxxx}\_T)}, where \textit{xxxx} is the +uppercase version of the name (according to the proposed naming +convention). The keyword \texttt{APIENTRY} is needed to be compatible +between different platforms. The \GLFW\ include file \texttt{GL/glfw.h} +always makes sure that \texttt{APIENTRY} is properly defined, regardless +of which platform the program is compiled on. + +In other words, for the function \textbf{glGetCompressedTexImageARB} we +get: + +\begin{lstlisting} +typedef void (APIENTRY * GLGETCOMPRESSEDTEXIMAGEARB_T) + (GLenum target, GLint level, void *img); +\end{lstlisting} + + + +%------------------------------------------------------------------------- +% Index +%------------------------------------------------------------------------- +% ... + +\end{document} diff --git a/docs/readme.txt b/docs/readme.txt new file mode 100644 index 00000000..f34521a2 --- /dev/null +++ b/docs/readme.txt @@ -0,0 +1,52 @@ +Introduction +------------ + +The GLFW documentation is written in LaTeX. Besides being powerful, LaTeX is +also very attractive since all the necessary tools for dealing with LaTeX +documentation are both free and ported to a wide variety of platforms. Another +advantage is that the LaTeX files are written in plain text, which means that +version control systems such as CVS handle them perfectly without having to +treat the documents as binary files. + + +The documents +------------- + +There are two main documents: + + glfwrm.tex - The GLFW Reference Manual + glfwug.tex - The GLFW Users Guide + +In addition, there is a common LaTeX style file that sets up things +such as page formatting and useful macros: + + glfwdoc.sty - Common GLFW document styles and macros + + +Requirements +------------ + +Of course you need LaTeX installed on your system in order to compile the GLFW +documentation. If you are using a Unix-like operating system, then your +package system most likely has a version of LaTeX adapted for your system. If +not, the easiest way to get a full LaTeX system is to download/get the TeXLive +CD from http://www.tug.org/texlive/. It has all the necessary software for +Windows, Mac OS X and most popular Unix-like operating systems. + +A number of LaTeX packages have to be installed in order to compile the +GLFW documentation successfully: + + color + fancyhdr + hyperref + lastpage + listings + needspace + textcase + times + titling + +These packages are all available on the TeXLive CD. Just make sure that +you have checked all these packages when installing TeXLive, or get them +in some other way if you do not have the TeXLive CD. + diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 00000000..a6282a14 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,37 @@ +# This line is used to link with static libraries +# Note that the library list should be updated to be obtained from +# the main CMakeLists.txt +link_libraries(libglfwStatic ${GLFW_LIBRARIES} ${OPENGL_glu_LIBRARY}) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include ${OPENGL_INCLUDE_DIR}) + +add_executable(listmodes listmodes.c) + +if(APPLE) + # Set fancy names for bundles + add_executable(Boing MACOSX_BUNDLE boing.c) + add_executable(Gears MACOSX_BUNDLE gears.c) + add_executable("Split View" MACOSX_BUNDLE splitview.c) + add_executable(Triangle MACOSX_BUNDLE triangle.c) + add_executable(Wave MACOSX_BUNDLE wave.c) +else(APPLE) + # Set boring names for executables + add_executable(boing WIN32 boing.c) + add_executable(gears WIN32 gears.c) + add_executable(splitview WIN32 splitview.c) + add_executable(triangle WIN32 triangle.c) + add_executable(wave WIN32 wave.c) +endif(APPLE) + +if(MSVC) + # Tell MSVC to use main instead of WinMain for Windows subsystem executables + set_target_properties(boing gears splitview triangle wave PROPERTIES LINK_FLAGS "/ENTRY:mainCRTStartup") +endif(MSVC) + +if(CYGWIN) + # Set cross-compile and subsystem compile and link flags + set_target_properties(boing gears listmodes splitview triangle wave PROPERTIES COMPILE_FLAGS "-mno-cygwin") + set_target_properties(boing gears splitview triangle wave PROPERTIES LINK_FLAGS "-mno-cygwin -mwindows") + set_target_properties(listmodes PROPERTIES LINK_FLAGS "-mno-cygwin -mconsole") +endif(CYGWIN) + diff --git a/examples/boing.c b/examples/boing.c new file mode 100644 index 00000000..451445b0 --- /dev/null +++ b/examples/boing.c @@ -0,0 +1,615 @@ +/***************************************************************************** + * Title: GLBoing + * Desc: Tribute to Amiga Boing. + * Author: Jim Brooks + * Original Amiga authors were R.J. Mical and Dale Luck. + * GLFW conversion by Marcus Geelnard + * Notes: - 360' = 2*PI [radian] + * + * - Distances between objects are created by doing a relative + * Z translations. + * + * - Although OpenGL enticingly supports alpha-blending, + * the shadow of the original Boing didn't affect the color + * of the grid. + * + * - [Marcus] Changed timing scheme from interval driven to frame- + * time based animation steps (which results in much smoother + * movement) + * + * History of Amiga Boing: + * + * Boing was demonstrated on the prototype Amiga (codenamed "Lorraine") in + * 1985. According to legend, it was written ad-hoc in one night by + * R. J. Mical and Dale Luck. Because the bouncing ball animation was so fast + * and smooth, attendees did not believe the Amiga prototype was really doing + * the rendering. Suspecting a trick, they began looking around the booth for + * a hidden computer or VCR. + *****************************************************************************/ + +#include +#include +#include +#include + + +/***************************************************************************** + * Various declarations and macros + *****************************************************************************/ + +/* Prototypes */ +void init( void ); +void display( void ); +void reshape( int w, int h ); +void DrawBoingBall( void ); +void BounceBall( double dt ); +void DrawBoingBallBand( GLfloat long_lo, GLfloat long_hi ); +void DrawGrid( void ); + +#define RADIUS 70.f +#define STEP_LONGITUDE 22.5f /* 22.5 makes 8 bands like original Boing */ +#define STEP_LATITUDE 22.5f + +#define DIST_BALL (RADIUS * 2.f + RADIUS * 0.1f) + +#define VIEW_SCENE_DIST (DIST_BALL * 3.f + 200.f)/* distance from viewer to middle of boing area */ +#define GRID_SIZE (RADIUS * 4.5f) /* length (width) of grid */ +#define BOUNCE_HEIGHT (RADIUS * 2.1f) +#define BOUNCE_WIDTH (RADIUS * 2.1f) + +#define SHADOW_OFFSET_X -20.f +#define SHADOW_OFFSET_Y 10.f +#define SHADOW_OFFSET_Z 0.f + +#define WALL_L_OFFSET 0.f +#define WALL_R_OFFSET 5.f + +/* Animation speed (50.0 mimics the original GLUT demo speed) */ +#define ANIMATION_SPEED 50.f + +/* Maximum allowed delta time per physics iteration */ +#define MAX_DELTA_T 0.02f + +/* Draw ball, or its shadow */ +typedef enum { DRAW_BALL, DRAW_BALL_SHADOW } DRAW_BALL_ENUM; + +/* Vertex type */ +typedef struct {float x; float y; float z;} vertex_t; + +/* Global vars */ +GLfloat deg_rot_y = 0.f; +GLfloat deg_rot_y_inc = 2.f; +GLfloat ball_x = -RADIUS; +GLfloat ball_y = -RADIUS; +GLfloat ball_x_inc = 1.f; +GLfloat ball_y_inc = 2.f; +DRAW_BALL_ENUM drawBallHow; +double t; +double t_old = 0.f; +double dt; + +/* Random number generator */ +#ifndef RAND_MAX + #define RAND_MAX 4095 +#endif + +/* PI */ +#ifndef M_PI + #define M_PI 3.1415926535897932384626433832795 +#endif + + +/***************************************************************************** + * Truncate a degree. + *****************************************************************************/ +GLfloat TruncateDeg( GLfloat deg ) +{ + if ( deg >= 360.f ) + return (deg - 360.f); + else + return deg; +} + +/***************************************************************************** + * Convert a degree (360-based) into a radian. + * 360' = 2 * PI + *****************************************************************************/ +double deg2rad( double deg ) +{ + return deg / 360 * (2 * M_PI); +} + +/***************************************************************************** + * 360' sin(). + *****************************************************************************/ +double sin_deg( double deg ) +{ + return sin( deg2rad( deg ) ); +} + +/***************************************************************************** + * 360' cos(). + *****************************************************************************/ +double cos_deg( double deg ) +{ + return cos( deg2rad( deg ) ); +} + +/***************************************************************************** + * Compute a cross product (for a normal vector). + * + * c = a x b + *****************************************************************************/ +void CrossProduct( vertex_t a, vertex_t b, vertex_t c, vertex_t *n ) +{ + GLfloat u1, u2, u3; + GLfloat v1, v2, v3; + + u1 = b.x - a.x; + u2 = b.y - a.y; + u3 = b.y - a.z; + + v1 = c.x - a.x; + v2 = c.y - a.y; + v3 = c.z - a.z; + + n->x = u2 * v3 - v2 * v3; + n->y = u3 * v1 - v3 * u1; + n->z = u1 * v2 - v1 * u2; +} + +/***************************************************************************** + * Calculate the angle to be passed to gluPerspective() so that a scene + * is visible. This function originates from the OpenGL Red Book. + * + * Parms : size + * The size of the segment when the angle is intersected at "dist" + * (ie at the outermost edge of the angle of vision). + * + * dist + * Distance from viewpoint to scene. + *****************************************************************************/ +GLfloat PerspectiveAngle( GLfloat size, + GLfloat dist ) +{ + GLfloat radTheta, degTheta; + + radTheta = 2.f * (GLfloat) atan2( size / 2.f, dist ); + degTheta = (180.f * radTheta) / (GLfloat) M_PI; + return degTheta; +} + + + +#define BOING_DEBUG 0 + + +/***************************************************************************** + * init() + *****************************************************************************/ +void init( void ) +{ + /* + * Clear background. + */ + glClearColor( 0.55f, 0.55f, 0.55f, 0.f ); + + glShadeModel( GL_FLAT ); +} + + +/***************************************************************************** + * display() + *****************************************************************************/ +void display(void) +{ + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + glPushMatrix(); + + drawBallHow = DRAW_BALL_SHADOW; + DrawBoingBall(); + + DrawGrid(); + + drawBallHow = DRAW_BALL; + DrawBoingBall(); + + glPopMatrix(); + glFlush(); +} + + +/***************************************************************************** + * reshape() + *****************************************************************************/ +void reshape( int w, int h ) +{ + glViewport( 0, 0, (GLsizei)w, (GLsizei)h ); + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + + gluPerspective( PerspectiveAngle( RADIUS * 2, 200 ), + (GLfloat)w / (GLfloat)h, + 1.0, + VIEW_SCENE_DIST ); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + gluLookAt( 0.0, 0.0, VIEW_SCENE_DIST,/* eye */ + 0.0, 0.0, 0.0, /* center of vision */ + 0.0, -1.0, 0.0 ); /* up vector */ +} + + +/***************************************************************************** + * Draw the Boing ball. + * + * The Boing ball is sphere in which each facet is a rectangle. + * Facet colors alternate between red and white. + * The ball is built by stacking latitudinal circles. Each circle is composed + * of a widely-separated set of points, so that each facet is noticably large. + *****************************************************************************/ +void DrawBoingBall( void ) +{ + GLfloat lon_deg; /* degree of longitude */ + double dt_total, dt2; + + glPushMatrix(); + glMatrixMode( GL_MODELVIEW ); + + /* + * Another relative Z translation to separate objects. + */ + glTranslatef( 0.0, 0.0, DIST_BALL ); + + /* Update ball position and rotation (iterate if necessary) */ + dt_total = dt; + while( dt_total > 0.0 ) + { + dt2 = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total; + dt_total -= dt2; + BounceBall( dt2 ); + deg_rot_y = TruncateDeg( deg_rot_y + deg_rot_y_inc*((float)dt2*ANIMATION_SPEED) ); + } + + /* Set ball position */ + glTranslatef( ball_x, ball_y, 0.0 ); + + /* + * Offset the shadow. + */ + if ( drawBallHow == DRAW_BALL_SHADOW ) + { + glTranslatef( SHADOW_OFFSET_X, + SHADOW_OFFSET_Y, + SHADOW_OFFSET_Z ); + } + + /* + * Tilt the ball. + */ + glRotatef( -20.0, 0.0, 0.0, 1.0 ); + + /* + * Continually rotate ball around Y axis. + */ + glRotatef( deg_rot_y, 0.0, 1.0, 0.0 ); + + /* + * Set OpenGL state for Boing ball. + */ + glCullFace( GL_FRONT ); + glEnable( GL_CULL_FACE ); + glEnable( GL_NORMALIZE ); + + /* + * Build a faceted latitude slice of the Boing ball, + * stepping same-sized vertical bands of the sphere. + */ + for ( lon_deg = 0; + lon_deg < 180; + lon_deg += STEP_LONGITUDE ) + { + /* + * Draw a latitude circle at this longitude. + */ + DrawBoingBallBand( lon_deg, + lon_deg + STEP_LONGITUDE ); + } + + glPopMatrix(); + + return; +} + + +/***************************************************************************** + * Bounce the ball. + *****************************************************************************/ +void BounceBall( double dt ) +{ + GLfloat sign; + GLfloat deg; + + /* Bounce on walls */ + if ( ball_x > (BOUNCE_WIDTH/2 + WALL_R_OFFSET ) ) + { + ball_x_inc = -0.5f - 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX; + deg_rot_y_inc = -deg_rot_y_inc; + } + if ( ball_x < -(BOUNCE_HEIGHT/2 + WALL_L_OFFSET) ) + { + ball_x_inc = 0.5f + 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX; + deg_rot_y_inc = -deg_rot_y_inc; + } + + /* Bounce on floor / roof */ + if ( ball_y > BOUNCE_HEIGHT/2 ) + { + ball_y_inc = -0.75f - 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX; + } + if ( ball_y < -BOUNCE_HEIGHT/2*0.85 ) + { + ball_y_inc = 0.75f + 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX; + } + + /* Update ball position */ + ball_x += ball_x_inc * ((float)dt*ANIMATION_SPEED); + ball_y += ball_y_inc * ((float)dt*ANIMATION_SPEED); + + /* + * Simulate the effects of gravity on Y movement. + */ + if ( ball_y_inc < 0 ) sign = -1.0; else sign = 1.0; + + deg = (ball_y + BOUNCE_HEIGHT/2) * 90 / BOUNCE_HEIGHT; + if ( deg > 80 ) deg = 80; + if ( deg < 10 ) deg = 10; + + ball_y_inc = sign * 4.f * (float) sin_deg( deg ); +} + + +/***************************************************************************** + * Draw a faceted latitude band of the Boing ball. + * + * Parms: long_lo, long_hi + * Low and high longitudes of slice, resp. + *****************************************************************************/ +void DrawBoingBallBand( GLfloat long_lo, + GLfloat long_hi ) +{ + vertex_t vert_ne; /* "ne" means south-east, so on */ + vertex_t vert_nw; + vertex_t vert_sw; + vertex_t vert_se; + vertex_t vert_norm; + GLfloat lat_deg; + static int colorToggle = 0; + + /* + * Iterate thru the points of a latitude circle. + * A latitude circle is a 2D set of X,Z points. + */ + for ( lat_deg = 0; + lat_deg <= (360 - STEP_LATITUDE); + lat_deg += STEP_LATITUDE ) + { + /* + * Color this polygon with red or white. + */ + if ( colorToggle ) + glColor3f( 0.8f, 0.1f, 0.1f ); + else + glColor3f( 0.95f, 0.95f, 0.95f ); +#if 0 + if ( lat_deg >= 180 ) + if ( colorToggle ) + glColor3f( 0.1f, 0.8f, 0.1f ); + else + glColor3f( 0.5f, 0.5f, 0.95f ); +#endif + colorToggle = ! colorToggle; + + /* + * Change color if drawing shadow. + */ + if ( drawBallHow == DRAW_BALL_SHADOW ) + glColor3f( 0.35f, 0.35f, 0.35f ); + + /* + * Assign each Y. + */ + vert_ne.y = vert_nw.y = (float) cos_deg(long_hi) * RADIUS; + vert_sw.y = vert_se.y = (float) cos_deg(long_lo) * RADIUS; + + /* + * Assign each X,Z with sin,cos values scaled by latitude radius indexed by longitude. + * Eg, long=0 and long=180 are at the poles, so zero scale is sin(longitude), + * while long=90 (sin(90)=1) is at equator. + */ + vert_ne.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); + vert_se.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo )); + vert_nw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); + vert_sw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo )); + + vert_ne.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); + vert_se.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo )); + vert_nw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); + vert_sw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo )); + + /* + * Draw the facet. + */ + glBegin( GL_POLYGON ); + + CrossProduct( vert_ne, vert_nw, vert_sw, &vert_norm ); + glNormal3f( vert_norm.x, vert_norm.y, vert_norm.z ); + + glVertex3f( vert_ne.x, vert_ne.y, vert_ne.z ); + glVertex3f( vert_nw.x, vert_nw.y, vert_nw.z ); + glVertex3f( vert_sw.x, vert_sw.y, vert_sw.z ); + glVertex3f( vert_se.x, vert_se.y, vert_se.z ); + + glEnd(); + +#if BOING_DEBUG + printf( "----------------------------------------------------------- \n" ); + printf( "lat = %f long_lo = %f long_hi = %f \n", lat_deg, long_lo, long_hi ); + printf( "vert_ne x = %.8f y = %.8f z = %.8f \n", vert_ne.x, vert_ne.y, vert_ne.z ); + printf( "vert_nw x = %.8f y = %.8f z = %.8f \n", vert_nw.x, vert_nw.y, vert_nw.z ); + printf( "vert_se x = %.8f y = %.8f z = %.8f \n", vert_se.x, vert_se.y, vert_se.z ); + printf( "vert_sw x = %.8f y = %.8f z = %.8f \n", vert_sw.x, vert_sw.y, vert_sw.z ); +#endif + + } + + /* + * Toggle color so that next band will opposite red/white colors than this one. + */ + colorToggle = ! colorToggle; + + /* + * This circular band is done. + */ + return; +} + + +/***************************************************************************** + * Draw the purple grid of lines, behind the Boing ball. + * When the Workbench is dropped to the bottom, Boing shows 12 rows. + *****************************************************************************/ +void DrawGrid( void ) +{ + int row, col; + const int rowTotal = 12; /* must be divisible by 2 */ + const int colTotal = rowTotal; /* must be same as rowTotal */ + const GLfloat widthLine = 2.0; /* should be divisible by 2 */ + const GLfloat sizeCell = GRID_SIZE / rowTotal; + const GLfloat z_offset = -40.0; + GLfloat xl, xr; + GLfloat yt, yb; + + glPushMatrix(); + glDisable( GL_CULL_FACE ); + + /* + * Another relative Z translation to separate objects. + */ + glTranslatef( 0.0, 0.0, DIST_BALL ); + + /* + * Draw vertical lines (as skinny 3D rectangles). + */ + for ( col = 0; col <= colTotal; col++ ) + { + /* + * Compute co-ords of line. + */ + xl = -GRID_SIZE / 2 + col * sizeCell; + xr = xl + widthLine; + + yt = GRID_SIZE / 2; + yb = -GRID_SIZE / 2 - widthLine; + + glBegin( GL_POLYGON ); + + glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */ + + glVertex3f( xr, yt, z_offset ); /* NE */ + glVertex3f( xl, yt, z_offset ); /* NW */ + glVertex3f( xl, yb, z_offset ); /* SW */ + glVertex3f( xr, yb, z_offset ); /* SE */ + + glEnd(); + } + + /* + * Draw horizontal lines (as skinny 3D rectangles). + */ + for ( row = 0; row <= rowTotal; row++ ) + { + /* + * Compute co-ords of line. + */ + yt = GRID_SIZE / 2 - row * sizeCell; + yb = yt - widthLine; + + xl = -GRID_SIZE / 2; + xr = GRID_SIZE / 2 + widthLine; + + glBegin( GL_POLYGON ); + + glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */ + + glVertex3f( xr, yt, z_offset ); /* NE */ + glVertex3f( xl, yt, z_offset ); /* NW */ + glVertex3f( xl, yb, z_offset ); /* SW */ + glVertex3f( xr, yb, z_offset ); /* SE */ + + glEnd(); + } + + glPopMatrix(); + + return; +} + + +/*======================================================================* + * main() + *======================================================================*/ + +int main( void ) +{ + int running; + + /* Init GLFW */ + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + if( !glfwOpenWindow( 400,400, 0,0,0,0, 16,0, GLFW_WINDOW ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + glfwSetWindowTitle( "Boing (classic Amiga demo)" ); + glfwSetWindowSizeCallback( reshape ); + glfwEnable( GLFW_STICKY_KEYS ); + glfwSwapInterval( 1 ); + glfwSetTime( 0.0 ); + + init(); + + /* Main loop */ + do + { + /* Timing */ + t = glfwGetTime(); + dt = t - t_old; + t_old = t; + + /* Draw one frame */ + display(); + + /* Swap buffers */ + glfwSwapBuffers(); + + /* Check if we are still running */ + running = !glfwGetKey( GLFW_KEY_ESC ) && + glfwGetWindowParam( GLFW_OPENED ); + } + while( running ); + + glfwTerminate(); + exit( EXIT_SUCCESS ); +} + diff --git a/examples/gears.c b/examples/gears.c new file mode 100644 index 00000000..5ad484db --- /dev/null +++ b/examples/gears.c @@ -0,0 +1,373 @@ +/* + * 3-D gear wheels. This program is in the public domain. + * + * Command line options: + * -info print GL implementation information + * -exit automatically exit after 30 seconds + * + * + * Brian Paul + * + * + * Marcus Geelnard: + * - Conversion to GLFW + * - Time based rendering (frame rate independent) + * - Slightly modified camera that should work better for stereo viewing + * + * + * Camilla Berglund: + * - Removed FPS counter (this is not a benchmark) + * - Added a few comments + * - Enabled vsync + */ + + +#include +#include +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.141592654 +#endif + +/* The program exits when this is zero. + */ +static int running = 1; + +/* If non-zero, the program exits after that many seconds + */ +static int autoexit = 0; + +/** + + Draw a gear wheel. You'll probably want to call this function when + building a display list since we do a lot of trig here. + + Input: inner_radius - radius of hole at center + outer_radius - radius at center of teeth + width - width of gear teeth - number of teeth + tooth_depth - depth of tooth + + **/ + +static void +gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, + GLint teeth, GLfloat tooth_depth) +{ + GLint i; + GLfloat r0, r1, r2; + GLfloat angle, da; + GLfloat u, v, len; + + r0 = inner_radius; + r1 = outer_radius - tooth_depth / 2.f; + r2 = outer_radius + tooth_depth / 2.f; + + da = 2.f * (float) M_PI / teeth / 4.f; + + glShadeModel(GL_FLAT); + + glNormal3f(0.f, 0.f, 1.f); + + /* draw front face */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); + if (i < teeth) { + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); + } + } + glEnd(); + + /* draw front sides of teeth */ + glBegin(GL_QUADS); + da = 2.f * (float) M_PI / teeth / 4.f; + for (i = 0; i < teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); + glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), width * 0.5f); + glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), width * 0.5f); + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); + } + glEnd(); + + glNormal3f(0.0, 0.0, -1.0); + + /* draw back face */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); + if (i < teeth) { + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); + } + } + glEnd(); + + /* draw back sides of teeth */ + glBegin(GL_QUADS); + da = 2.f * (float) M_PI / teeth / 4.f; + for (i = 0; i < teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); + glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), -width * 0.5f); + glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), -width * 0.5f); + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); + } + glEnd(); + + /* draw outward faces of teeth */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i < teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); + u = r2 * (float) cos(angle + da) - r1 * (float) cos(angle); + v = r2 * (float) sin(angle + da) - r1 * (float) sin(angle); + len = (float) sqrt(u * u + v * v); + u /= len; + v /= len; + glNormal3f(v, -u, 0.0); + glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), width * 0.5f); + glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), -width * 0.5f); + glNormal3f((float) cos(angle), (float) sin(angle), 0.f); + glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), width * 0.5f); + glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), -width * 0.5f); + u = r1 * (float) cos(angle + 3 * da) - r2 * (float) cos(angle + 2 * da); + v = r1 * (float) sin(angle + 3 * da) - r2 * (float) sin(angle + 2 * da); + glNormal3f(v, -u, 0.f); + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); + glNormal3f((float) cos(angle), (float) sin(angle), 0.f); + } + + glVertex3f(r1 * (float) cos(0), r1 * (float) sin(0), width * 0.5f); + glVertex3f(r1 * (float) cos(0), r1 * (float) sin(0), -width * 0.5f); + + glEnd(); + + glShadeModel(GL_SMOOTH); + + /* draw inside radius cylinder */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + glNormal3f(-(float) cos(angle), -(float) sin(angle), 0.f); + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); + } + glEnd(); + +} + + +static GLfloat view_rotx = 20.f, view_roty = 30.f, view_rotz = 0.f; +static GLint gear1, gear2, gear3; +static GLfloat angle = 0.f; + +/* OpenGL draw function & timing */ +static void draw(void) +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glPushMatrix(); + glRotatef(view_rotx, 1.0, 0.0, 0.0); + glRotatef(view_roty, 0.0, 1.0, 0.0); + glRotatef(view_rotz, 0.0, 0.0, 1.0); + + glPushMatrix(); + glTranslatef(-3.0, -2.0, 0.0); + glRotatef(angle, 0.0, 0.0, 1.0); + glCallList(gear1); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(3.1f, -2.f, 0.f); + glRotatef(-2.f * angle - 9.f, 0.f, 0.f, 1.f); + glCallList(gear2); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(-3.1f, 4.2f, 0.f); + glRotatef(-2.f * angle - 25.f, 0.f, 0.f, 1.f); + glCallList(gear3); + glPopMatrix(); + + glPopMatrix(); +} + + +/* update animation parameters */ +static void animate(void) +{ + angle = 100.f * (float) glfwGetTime(); +} + + +/* change view angle, exit upon ESC */ +void key( int k, int action ) +{ + if( action != GLFW_PRESS ) return; + + switch (k) { + case 'Z': + if( glfwGetKey( GLFW_KEY_LSHIFT ) ) + view_rotz -= 5.0; + else + view_rotz += 5.0; + break; + case GLFW_KEY_ESC: + running = 0; + break; + case GLFW_KEY_UP: + view_rotx += 5.0; + break; + case GLFW_KEY_DOWN: + view_rotx -= 5.0; + break; + case GLFW_KEY_LEFT: + view_roty += 5.0; + break; + case GLFW_KEY_RIGHT: + view_roty -= 5.0; + break; + default: + return; + } +} + + +/* new window size */ +void reshape( int width, int height ) +{ + GLfloat h = (GLfloat) height / (GLfloat) width; + GLfloat xmax, znear, zfar; + + znear = 5.0f; + zfar = 30.0f; + xmax = znear * 0.5f; + + glViewport( 0, 0, (GLint) width, (GLint) height ); + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glFrustum( -xmax, xmax, -xmax*h, xmax*h, znear, zfar ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + glTranslatef( 0.0, 0.0, -20.0 ); +} + + +/* program & OpenGL initialization */ +static void init(int argc, char *argv[]) +{ + static GLfloat pos[4] = {5.f, 5.f, 10.f, 0.f}; + static GLfloat red[4] = {0.8f, 0.1f, 0.f, 1.f}; + static GLfloat green[4] = {0.f, 0.8f, 0.2f, 1.f}; + static GLfloat blue[4] = {0.2f, 0.2f, 1.f, 1.f}; + GLint i; + + glLightfv(GL_LIGHT0, GL_POSITION, pos); + glEnable(GL_CULL_FACE); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_DEPTH_TEST); + + /* make the gears */ + gear1 = glGenLists(1); + glNewList(gear1, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); + gear(1.f, 4.f, 1.f, 20, 0.7f); + glEndList(); + + gear2 = glGenLists(1); + glNewList(gear2, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); + gear(0.5f, 2.f, 2.f, 10, 0.7f); + glEndList(); + + gear3 = glGenLists(1); + glNewList(gear3, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); + gear(1.3f, 2.f, 0.5f, 10, 0.7f); + glEndList(); + + glEnable(GL_NORMALIZE); + + for ( i=1; i +#include + +// Maximum number of modes that we want to list +#define MAX_NUM_MODES 400 + + +//======================================================================== +// main() +//======================================================================== + +int main( void ) +{ + GLFWvidmode dtmode, modes[ MAX_NUM_MODES ]; + int modecount, i; + + // Initialize GLFW + if( !glfwInit() ) + { + return 0; + } + + // Show desktop video mode + glfwGetDesktopMode( &dtmode ); + printf( "Desktop mode: %d x %d x %d\n\n", + dtmode.Width, dtmode.Height, dtmode.RedBits + + dtmode.GreenBits + dtmode.BlueBits ); + + // List available video modes + modecount = glfwGetVideoModes( modes, MAX_NUM_MODES ); + printf( "Available modes:\n" ); + for( i = 0; i < modecount; i ++ ) + { + printf( "%3d: %d x %d x %d\n", i, + modes[i].Width, modes[i].Height, modes[i].RedBits + + modes[i].GreenBits + modes[i].BlueBits ); + } + + // Terminate GLFW + glfwTerminate(); + + return 0; +} diff --git a/examples/mipmaps.c b/examples/mipmaps.c new file mode 100644 index 00000000..59bbef2e --- /dev/null +++ b/examples/mipmaps.c @@ -0,0 +1,122 @@ +//======================================================================== +// This is an example program for the GLFW library +// +// It shows texture loading with mipmap generation and rendering with +// trilienar texture filtering +//======================================================================== + +#include +#include + +#include + +int main( void ) +{ + int width, height, x; + double time; + GLboolean running; + GLuint textureID; + char* texturePath = "mipmaps.tga"; + + // Initialise GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + // Open OpenGL window + if( !glfwOpenWindow( 640, 480, 0,0,0,0, 0,0, GLFW_WINDOW ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + glfwSetWindowTitle( "Trilinear interpolation" ); + + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Enable vertical sync (on cards that support it) + glfwSwapInterval( 1 ); + + // Generate and bind our texture ID + glGenTextures( 1, &textureID ); + glBindTexture( GL_TEXTURE_2D, textureID ); + + // Load texture from file into video memory, including mipmap levels + if( !glfwLoadTexture2D( texturePath, GLFW_BUILD_MIPMAPS_BIT ) ) + { + fprintf( stderr, "Failed to load texture %s\n", texturePath ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + // Use trilinear interpolation (GL_LINEAR_MIPMAP_LINEAR) + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + GL_LINEAR ); + + // Enable plain 2D texturing + glEnable( GL_TEXTURE_2D ); + + running = GL_TRUE; + while( running ) + { + // Get time and mouse position + time = glfwGetTime(); + glfwGetMousePos( &x, NULL ); + + // Get window size (may be different than the requested size) + glfwGetWindowSize( &width, &height ); + height = height > 0 ? height : 1; + + // Set viewport + glViewport( 0, 0, width, height ); + + // Clear color buffer + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f); + glClear( GL_COLOR_BUFFER_BIT ); + + // Select and setup the projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( 65.0f, (GLfloat)width / (GLfloat)height, 1.0f, + 50.0f ); + + // Select and setup the modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 0.0f, 3.0f, -20.0f, // Eye-position + 0.0f, -4.0f, -11.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + + // Draw a textured quad + glRotatef( 0.05f * (GLfloat)x + (GLfloat)time * 5.0f, 0.0f, 1.0f, 0.0f ); + glBegin( GL_QUADS ); + glTexCoord2f( -20.0f, 20.0f ); + glVertex3f( -50.0f, 0.0f, -50.0f ); + glTexCoord2f( 20.0f, 20.0f ); + glVertex3f( 50.0f, 0.0f, -50.0f ); + glTexCoord2f( 20.0f, -20.0f ); + glVertex3f( 50.0f, 0.0f, 50.0f ); + glTexCoord2f( -20.0f, -20.0f ); + glVertex3f( -50.0f, 0.0f, 50.0f ); + glEnd(); + + // Swap buffers + glfwSwapBuffers(); + + // Check if the ESC key was pressed or the window was closed + running = !glfwGetKey( GLFW_KEY_ESC ) && + glfwGetWindowParam( GLFW_OPENED ); + } + + // Close OpenGL window and terminate GLFW + glfwTerminate(); + + exit( EXIT_SUCCESS ); +} + diff --git a/examples/mipmaps.tga b/examples/mipmaps.tga new file mode 100644 index 00000000..55f913b0 Binary files /dev/null and b/examples/mipmaps.tga differ diff --git a/examples/particles.c b/examples/particles.c new file mode 100644 index 00000000..403a9997 --- /dev/null +++ b/examples/particles.c @@ -0,0 +1,1152 @@ +//======================================================================== +// This is a simple, but cool particle engine (buzz-word meaning many +// small objects that are treated as points and drawn as textures +// projected on simple geometry). +// +// This demonstration generates a colorful fountain-like animation. It +// uses several advanced OpenGL teqhniques: +// +// 1) Lighting (per vertex) +// 2) Alpha blending +// 3) Fog +// 4) Texturing +// 5) Display lists (for drawing the static environment geometry) +// 6) Vertex arrays (for drawing the particles) +// 7) GL_EXT_separate_specular_color is used (if available) +// +// Even more so, this program uses multi threading. The program is +// essentialy divided into a main rendering thread and a particle physics +// calculation thread. My benchmarks under Windows 2000 on a single +// processor system show that running this program as two threads instead +// of a single thread means no difference (there may be a very marginal +// advantage for the multi threaded case). On dual processor systems I +// have had reports of 5-25% of speed increase when running this program +// as two threads instead of one thread. +// +// The default behaviour of this program is to use two threads. To force +// a single thread to be used, use the command line switch -s. +// +// To run a fixed length benchmark (60 s), use the command line switch -b. +// +// Benchmark results (640x480x16, best of three tests): +// +// CPU GFX 1 thread 2 threads +// Athlon XP 2700+ GeForce Ti4200 (oc) 757 FPS 759 FPS +// P4 2.8 GHz (SMT) GeForce FX5600 548 FPS 550 FPS +// +// One more thing: Press 'w' during the demo to toggle wireframe mode. +//======================================================================== + +#include +#include +#include +#include +#include + +// Define tokens for GL_EXT_separate_specular_color if not already defined +#ifndef GL_EXT_separate_specular_color +#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 +#define GL_SINGLE_COLOR_EXT 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA +#endif // GL_EXT_separate_specular_color + +// Some 's do not define M_PI +#ifndef M_PI +#define M_PI 3.141592654 +#endif + +// Desired fullscreen resolution +#define WIDTH 640 +#define HEIGHT 480 + + +//======================================================================== +// Type definitions +//======================================================================== + +typedef struct { float x,y,z; } VEC; + +// This structure is used for interleaved vertex arrays (see the +// DrawParticles function) - Note: This structure SHOULD be packed on most +// systems. It uses 32-bit fields on 32-bit boundaries, and is a multiple +// of 64 bits in total (6x32=3x64). If it does not work, try using pragmas +// or whatever to force the structure to be packed. +typedef struct { + GLfloat s, t; // Texture coordinates + GLuint rgba; // Color (four ubytes packed into an uint) + GLfloat x, y, z; // Vertex coordinates +} VERTEX; + + +//======================================================================== +// Program control global variables +//======================================================================== + +// "Running" flag (true if program shall continue to run) +int running; + +// Window dimensions +int width, height; + +// "wireframe" flag (true if we use wireframe view) +int wireframe; + +// "multithreading" flag (true if we use multithreading) +int multithreading; + +// Thread synchronization +struct { + double t; // Time (s) + float dt; // Time since last frame (s) + int p_frame; // Particle physics frame number + int d_frame; // Particle draw frame number + GLFWcond p_done; // Condition: particle physics done + GLFWcond d_done; // Condition: particle draw done + GLFWmutex particles_lock; // Particles data sharing mutex +} thread_sync; + + +//======================================================================== +// Texture declarations (we hard-code them into the source code, since +// they are so simple) +//======================================================================== + +#define P_TEX_WIDTH 8 // Particle texture dimensions +#define P_TEX_HEIGHT 8 +#define F_TEX_WIDTH 16 // Floor texture dimensions +#define F_TEX_HEIGHT 16 + +// Texture object IDs +GLuint particle_tex_id, floor_tex_id; + +// Particle texture (a simple spot) +const unsigned char particle_texture[ P_TEX_WIDTH * P_TEX_HEIGHT ] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x11, 0x22, 0x22, 0x11, 0x00, 0x00, + 0x00, 0x11, 0x33, 0x88, 0x77, 0x33, 0x11, 0x00, + 0x00, 0x22, 0x88, 0xff, 0xee, 0x77, 0x22, 0x00, + 0x00, 0x22, 0x77, 0xee, 0xff, 0x88, 0x22, 0x00, + 0x00, 0x11, 0x33, 0x77, 0x88, 0x33, 0x11, 0x00, + 0x00, 0x00, 0x11, 0x33, 0x22, 0x11, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// Floor texture (your basic checkered floor) +const unsigned char floor_texture[ F_TEX_WIDTH * F_TEX_HEIGHT ] = { + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0xff, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0xf0, 0xcc, 0xee, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x66, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xee, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0xf0, 0xf0, 0xf0, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x55, 0x30, 0x30, 0x44, 0x30, 0x30, + 0xf0, 0xdd, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x60, 0x30, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, 0xf0, 0xff, 0xf0, 0xf0, 0xdd, 0xf0, 0xf0, 0xff, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x55, 0x33, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, + 0x30, 0x44, 0x66, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xaa, 0xf0, 0xf0, 0xcc, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xdd, 0xf0, + 0x30, 0x30, 0x30, 0x77, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +}; + + +//======================================================================== +// These are fixed constants that control the particle engine. In a +// modular world, these values should be variables... +//======================================================================== + +// Maximum number of particles +#define MAX_PARTICLES 3000 + +// Life span of a particle (in seconds) +#define LIFE_SPAN 8.0f + +// A new particle is born every [BIRTH_INTERVAL] second +#define BIRTH_INTERVAL (LIFE_SPAN/(float)MAX_PARTICLES) + +// Particle size (meters) +#define PARTICLE_SIZE 0.7f + +// Gravitational constant (m/s^2) +#define GRAVITY 9.8f + +// Base initial velocity (m/s) +#define VELOCITY 8.0f + +// Bounce friction (1.0 = no friction, 0.0 = maximum friction) +#define FRICTION 0.75f + +// "Fountain" height (m) +#define FOUNTAIN_HEIGHT 3.0f + +// Fountain radius (m) +#define FOUNTAIN_RADIUS 1.6f + +// Minimum delta-time for particle phisics (s) +#define MIN_DELTA_T (BIRTH_INTERVAL * 0.5f) + + +//======================================================================== +// Particle system global variables +//======================================================================== + +// This structure holds all state for a single particle +typedef struct { + float x,y,z; // Position in space + float vx,vy,vz; // Velocity vector + float r,g,b; // Color of particle + float life; // Life of particle (1.0 = newborn, < 0.0 = dead) + int active; // Tells if this particle is active +} PARTICLE; + +// Global vectors holding all particles. We use two vectors for double +// buffering. +static PARTICLE particles[ MAX_PARTICLES ]; + +// Global variable holding the age of the youngest particle +static float min_age; + +// Color of latest born particle (used for fountain lighting) +static float glow_color[4]; + +// Position of latest born particle (used for fountain lighting) +static float glow_pos[4]; + + +//======================================================================== +// Object material and fog configuration constants +//======================================================================== + +const GLfloat fountain_diffuse[4] = {0.7f,1.0f,1.0f,1.0f}; +const GLfloat fountain_specular[4] = {1.0f,1.0f,1.0f,1.0f}; +const GLfloat fountain_shininess = 12.0f; +const GLfloat floor_diffuse[4] = {1.0f,0.6f,0.6f,1.0f}; +const GLfloat floor_specular[4] = {0.6f,0.6f,0.6f,1.0f}; +const GLfloat floor_shininess = 18.0f; +const GLfloat fog_color[4] = {0.1f, 0.1f, 0.1f, 1.0f}; + + +//======================================================================== +// InitParticle() - Initialize a new particle +//======================================================================== + +void InitParticle( PARTICLE *p, double t ) +{ + float xy_angle, velocity; + + // Start position of particle is at the fountain blow-out + p->x = 0.0f; + p->y = 0.0f; + p->z = FOUNTAIN_HEIGHT; + + // Start velocity is up (Z)... + p->vz = 0.7f + (0.3f/4096.f) * (float) (rand() & 4095); + + // ...and a randomly chosen X/Y direction + xy_angle = (2.f * (float)M_PI / 4096.f) * (float) (rand() & 4095); + p->vx = 0.4f * (float) cos( xy_angle ); + p->vy = 0.4f * (float) sin( xy_angle ); + + // Scale velocity vector according to a time-varying velocity + velocity = VELOCITY*(0.8f + 0.1f*(float)(sin( 0.5*t )+sin( 1.31*t ))); + p->vx *= velocity; + p->vy *= velocity; + p->vz *= velocity; + + // Color is time-varying + p->r = 0.7f + 0.3f * (float) sin( 0.34*t + 0.1 ); + p->g = 0.6f + 0.4f * (float) sin( 0.63*t + 1.1 ); + p->b = 0.6f + 0.4f * (float) sin( 0.91*t + 2.1 ); + + // Store settings for fountain glow lighting + glow_pos[0] = 0.4f * (float) sin( 1.34*t ); + glow_pos[1] = 0.4f * (float) sin( 3.11*t ); + glow_pos[2] = FOUNTAIN_HEIGHT + 1.0f; + glow_pos[3] = 1.0f; + glow_color[0] = p->r; + glow_color[1] = p->g; + glow_color[2] = p->b; + glow_color[3] = 1.0f; + + // The particle is new-born and active + p->life = 1.0f; + p->active = 1; +} + + +//======================================================================== +// UpdateParticle() - Update a particle +//======================================================================== + +#define FOUNTAIN_R2 (FOUNTAIN_RADIUS+PARTICLE_SIZE/2)*(FOUNTAIN_RADIUS+PARTICLE_SIZE/2) + +void UpdateParticle( PARTICLE *p, float dt ) +{ + // If the particle is not active, we need not do anything + if( !p->active ) + { + return; + } + + // The particle is getting older... + p->life = p->life - dt * (1.0f / LIFE_SPAN); + + // Did the particle die? + if( p->life <= 0.0f ) + { + p->active = 0; + return; + } + + // Update particle velocity (apply gravity) + p->vz = p->vz - GRAVITY * dt; + + // Update particle position + p->x = p->x + p->vx * dt; + p->y = p->y + p->vy * dt; + p->z = p->z + p->vz * dt; + + // Simple collision detection + response + if( p->vz < 0.0f ) + { + // Particles should bounce on the fountain (with friction) + if( (p->x*p->x + p->y*p->y) < FOUNTAIN_R2 && + p->z < (FOUNTAIN_HEIGHT + PARTICLE_SIZE/2) ) + { + p->vz = -FRICTION * p->vz; + p->z = FOUNTAIN_HEIGHT + PARTICLE_SIZE/2 + + FRICTION * (FOUNTAIN_HEIGHT + + PARTICLE_SIZE/2 - p->z); + } + + // Particles should bounce on the floor (with friction) + else if( p->z < PARTICLE_SIZE/2 ) + { + p->vz = -FRICTION * p->vz; + p->z = PARTICLE_SIZE/2 + + FRICTION * (PARTICLE_SIZE/2 - p->z); + } + + } +} + + +//======================================================================== +// ParticleEngine() - The main frame for the particle engine. Called once +// per frame. +//======================================================================== + +void ParticleEngine( double t, float dt ) +{ + int i; + float dt2; + + // Update particles (iterated several times per frame if dt is too + // large) + while( dt > 0.0f ) + { + // Calculate delta time for this iteration + dt2 = dt < MIN_DELTA_T ? dt : MIN_DELTA_T; + + // Update particles + for( i = 0; i < MAX_PARTICLES; i ++ ) + { + UpdateParticle( &particles[ i ], dt2 ); + } + + // Increase minimum age + min_age += dt2; + + // Should we create any new particle(s)? + while( min_age >= BIRTH_INTERVAL ) + { + min_age -= BIRTH_INTERVAL; + + // Find a dead particle to replace with a new one + for( i = 0; i < MAX_PARTICLES; i ++ ) + { + if( !particles[ i ].active ) + { + InitParticle( &particles[ i ], t + min_age ); + UpdateParticle( &particles[ i ], min_age ); + break; + } + } + } + + // Decrease frame delta time + dt -= dt2; + } +} + + +//======================================================================== +// DrawParticles() - Draw all active particles. We use OpenGL 1.1 vertex +// arrays for this in order to accelerate the drawing. +//======================================================================== + +#define BATCH_PARTICLES 70 // Number of particles to draw in each batch + // (70 corresponds to 7.5 KB = will not blow + // the L1 data cache on most CPUs) +#define PARTICLE_VERTS 4 // Number of vertices per particle + +void DrawParticles( double t, float dt ) +{ + int i, particle_count; + VERTEX vertex_array[ BATCH_PARTICLES * PARTICLE_VERTS ], *vptr; + float alpha; + GLuint rgba; + VEC quad_lower_left, quad_lower_right; + GLfloat mat[ 16 ]; + PARTICLE *pptr; + + // Here comes the real trick with flat single primitive objects (s.c. + // "billboards"): We must rotate the textured primitive so that it + // always faces the viewer (is coplanar with the view-plane). + // We: + // 1) Create the primitive around origo (0,0,0) + // 2) Rotate it so that it is coplanar with the view plane + // 3) Translate it according to the particle position + // Note that 1) and 2) is the same for all particles (done only once). + + // Get modelview matrix. We will only use the upper left 3x3 part of + // the matrix, which represents the rotation. + glGetFloatv( GL_MODELVIEW_MATRIX, mat ); + + // 1) & 2) We do it in one swift step: + // Although not obvious, the following six lines represent two matrix/ + // vector multiplications. The matrix is the inverse 3x3 rotation + // matrix (i.e. the transpose of the same matrix), and the two vectors + // represent the lower left corner of the quad, PARTICLE_SIZE/2 * + // (-1,-1,0), and the lower right corner, PARTICLE_SIZE/2 * (1,-1,0). + // The upper left/right corners of the quad is always the negative of + // the opposite corners (regardless of rotation). + quad_lower_left.x = (-PARTICLE_SIZE/2) * (mat[0] + mat[1]); + quad_lower_left.y = (-PARTICLE_SIZE/2) * (mat[4] + mat[5]); + quad_lower_left.z = (-PARTICLE_SIZE/2) * (mat[8] + mat[9]); + quad_lower_right.x = (PARTICLE_SIZE/2) * (mat[0] - mat[1]); + quad_lower_right.y = (PARTICLE_SIZE/2) * (mat[4] - mat[5]); + quad_lower_right.z = (PARTICLE_SIZE/2) * (mat[8] - mat[9]); + + // Don't update z-buffer, since all particles are transparent! + glDepthMask( GL_FALSE ); + + // Enable blending + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE ); + + // Select particle texture + if( !wireframe ) + { + glEnable( GL_TEXTURE_2D ); + glBindTexture( GL_TEXTURE_2D, particle_tex_id ); + } + + // Set up vertex arrays. We use interleaved arrays, which is easier to + // handle (in most situations) and it gives a linear memeory access + // access pattern (which may give better performance in some + // situations). GL_T2F_C4UB_V3F means: 2 floats for texture coords, + // 4 ubytes for color and 3 floats for vertex coord (in that order). + // Most OpenGL cards / drivers are optimized for this format. + glInterleavedArrays( GL_T2F_C4UB_V3F, 0, vertex_array ); + + // Is particle physics carried out in a separate thread? + if( multithreading ) + { + // Wait for particle physics thread to be done + glfwLockMutex( thread_sync.particles_lock ); + while( running && thread_sync.p_frame <= thread_sync.d_frame ) + { + glfwWaitCond( thread_sync.p_done, thread_sync.particles_lock, + 0.1 ); + } + + // Store the frame time and delta time for the physics thread + thread_sync.t = t; + thread_sync.dt = dt; + + // Update frame counter + thread_sync.d_frame ++; + } + else + { + // Perform particle physics in this thread + ParticleEngine( t, dt ); + } + + // Loop through all particles and build vertex arrays. + particle_count = 0; + vptr = vertex_array; + pptr = particles; + for( i = 0; i < MAX_PARTICLES; i ++ ) + { + if( pptr->active ) + { + // Calculate particle intensity (we set it to max during 75% + // of its life, then it fades out) + alpha = 4.0f * pptr->life; + if( alpha > 1.0f ) + { + alpha = 1.0f; + } + + // Convert color from float to 8-bit (store it in a 32-bit + // integer using endian independent type casting) + ((GLubyte *)&rgba)[0] = (GLubyte)(pptr->r * 255.0f); + ((GLubyte *)&rgba)[1] = (GLubyte)(pptr->g * 255.0f); + ((GLubyte *)&rgba)[2] = (GLubyte)(pptr->b * 255.0f); + ((GLubyte *)&rgba)[3] = (GLubyte)(alpha * 255.0f); + + // 3) Translate the quad to the correct position in modelview + // space and store its parameters in vertex arrays (we also + // store texture coord and color information for each vertex). + + // Lower left corner + vptr->s = 0.0f; + vptr->t = 0.0f; + vptr->rgba = rgba; + vptr->x = pptr->x + quad_lower_left.x; + vptr->y = pptr->y + quad_lower_left.y; + vptr->z = pptr->z + quad_lower_left.z; + vptr ++; + + // Lower right corner + vptr->s = 1.0f; + vptr->t = 0.0f; + vptr->rgba = rgba; + vptr->x = pptr->x + quad_lower_right.x; + vptr->y = pptr->y + quad_lower_right.y; + vptr->z = pptr->z + quad_lower_right.z; + vptr ++; + + // Upper right corner + vptr->s = 1.0f; + vptr->t = 1.0f; + vptr->rgba = rgba; + vptr->x = pptr->x - quad_lower_left.x; + vptr->y = pptr->y - quad_lower_left.y; + vptr->z = pptr->z - quad_lower_left.z; + vptr ++; + + // Upper left corner + vptr->s = 0.0f; + vptr->t = 1.0f; + vptr->rgba = rgba; + vptr->x = pptr->x - quad_lower_right.x; + vptr->y = pptr->y - quad_lower_right.y; + vptr->z = pptr->z - quad_lower_right.z; + vptr ++; + + // Increase count of drawable particles + particle_count ++; + } + + // If we have filled up one batch of particles, draw it as a set + // of quads using glDrawArrays. + if( particle_count >= BATCH_PARTICLES ) + { + // The first argument tells which primitive type we use (QUAD) + // The second argument tells the index of the first vertex (0) + // The last argument is the vertex count + glDrawArrays( GL_QUADS, 0, PARTICLE_VERTS * particle_count ); + particle_count = 0; + vptr = vertex_array; + } + + // Next particle + pptr ++; + } + + // We are done with the particle data: Unlock mutex and signal physics + // thread + if( multithreading ) + { + glfwUnlockMutex( thread_sync.particles_lock ); + glfwSignalCond( thread_sync.d_done ); + } + + // Draw final batch of particles (if any) + glDrawArrays( GL_QUADS, 0, PARTICLE_VERTS * particle_count ); + + // Disable vertex arrays (Note: glInterleavedArrays implicitly called + // glEnableClientState for vertex, texture coord and color arrays) + glDisableClientState( GL_VERTEX_ARRAY ); + glDisableClientState( GL_TEXTURE_COORD_ARRAY ); + glDisableClientState( GL_COLOR_ARRAY ); + + // Disable texturing and blending + glDisable( GL_TEXTURE_2D ); + glDisable( GL_BLEND ); + + // Allow Z-buffer updates again + glDepthMask( GL_TRUE ); +} + + +//======================================================================== +// Fountain geometry specification +//======================================================================== + +#define FOUNTAIN_SIDE_POINTS 14 +#define FOUNTAIN_SWEEP_STEPS 32 + +static const float fountain_side[ FOUNTAIN_SIDE_POINTS*2 ] = { + 1.2f, 0.0f, 1.0f, 0.2f, 0.41f, 0.3f, 0.4f, 0.35f, + 0.4f, 1.95f, 0.41f, 2.0f, 0.8f, 2.2f, 1.2f, 2.4f, + 1.5f, 2.7f, 1.55f,2.95f, 1.6f, 3.0f, 1.0f, 3.0f, + 0.5f, 3.0f, 0.0f, 3.0f +}; + +static const float fountain_normal[ FOUNTAIN_SIDE_POINTS*2 ] = { + 1.0000f, 0.0000f, 0.6428f, 0.7660f, 0.3420f, 0.9397f, 1.0000f, 0.0000f, + 1.0000f, 0.0000f, 0.3420f,-0.9397f, 0.4226f,-0.9063f, 0.5000f,-0.8660f, + 0.7660f,-0.6428f, 0.9063f,-0.4226f, 0.0000f,1.00000f, 0.0000f,1.00000f, + 0.0000f,1.00000f, 0.0000f,1.00000f +}; + + +//======================================================================== +// DrawFountain() - Draw a fountain +//======================================================================== + +void DrawFountain( void ) +{ + static GLuint fountain_list = 0; + double angle; + float x, y; + int m, n; + + // The first time, we build the fountain display list + if( !fountain_list ) + { + // Start recording of a new display list + fountain_list = glGenLists( 1 ); + glNewList( fountain_list, GL_COMPILE_AND_EXECUTE ); + + // Set fountain material + glMaterialfv( GL_FRONT, GL_DIFFUSE, fountain_diffuse ); + glMaterialfv( GL_FRONT, GL_SPECULAR, fountain_specular ); + glMaterialf( GL_FRONT, GL_SHININESS, fountain_shininess ); + + // Build fountain using triangle strips + for( n = 0; n < FOUNTAIN_SIDE_POINTS-1; n ++ ) + { + glBegin( GL_TRIANGLE_STRIP ); + for( m = 0; m <= FOUNTAIN_SWEEP_STEPS; m ++ ) + { + angle = (double) m * (2.0*M_PI/(double)FOUNTAIN_SWEEP_STEPS); + x = (float) cos( angle ); + y = (float) sin( angle ); + + // Draw triangle strip + glNormal3f( x * fountain_normal[ n*2+2 ], + y * fountain_normal[ n*2+2 ], + fountain_normal[ n*2+3 ] ); + glVertex3f( x * fountain_side[ n*2+2 ], + y * fountain_side[ n*2+2 ], + fountain_side[ n*2+3 ] ); + glNormal3f( x * fountain_normal[ n*2 ], + y * fountain_normal[ n*2 ], + fountain_normal[ n*2+1 ] ); + glVertex3f( x * fountain_side[ n*2 ], + y * fountain_side[ n*2 ], + fountain_side[ n*2+1 ] ); + } + glEnd(); + } + + // End recording of display list + glEndList(); + } + else + { + // Playback display list + glCallList( fountain_list ); + } +} + + +//======================================================================== +// TesselateFloor() - Recursive function for building variable tesselated +// floor +//======================================================================== + +void TesselateFloor( float x1, float y1, float x2, float y2, + int recursion ) +{ + float delta, x, y; + + // Last recursion? + if( recursion >= 5 ) + { + delta = 999999.0f; + } + else + { + x = (float) (fabs(x1) < fabs(x2) ? fabs(x1) : fabs(x2)); + y = (float) (fabs(y1) < fabs(y2) ? fabs(y1) : fabs(y2)); + delta = x*x + y*y; + } + + // Recurse further? + if( delta < 0.1f ) + { + x = (x1+x2) * 0.5f; + y = (y1+y2) * 0.5f; + TesselateFloor( x1,y1, x, y, recursion + 1 ); + TesselateFloor( x,y1, x2, y, recursion + 1 ); + TesselateFloor( x1, y, x,y2, recursion + 1 ); + TesselateFloor( x, y, x2,y2, recursion + 1 ); + } + else + { + glTexCoord2f( x1*30.0f, y1*30.0f ); + glVertex3f( x1*80.0f, y1*80.0f , 0.0f ); + glTexCoord2f( x2*30.0f, y1*30.0f ); + glVertex3f( x2*80.0f, y1*80.0f , 0.0f ); + glTexCoord2f( x2*30.0f, y2*30.0f ); + glVertex3f( x2*80.0f, y2*80.0f , 0.0f ); + glTexCoord2f( x1*30.0f, y2*30.0f ); + glVertex3f( x1*80.0f, y2*80.0f , 0.0f ); + } +} + + +//======================================================================== +// DrawFloor() - Draw floor. We builde the floor recursively, and let the +// tesselation in the centre (near x,y=0,0) be high, while the selleation +// around the edges be low. +//======================================================================== + +void DrawFloor( void ) +{ + static GLuint floor_list = 0; + + // Select floor texture + if( !wireframe ) + { + glEnable( GL_TEXTURE_2D ); + glBindTexture( GL_TEXTURE_2D, floor_tex_id ); + } + + // The first time, we build the floor display list + if( !floor_list ) + { + // Start recording of a new display list + floor_list = glGenLists( 1 ); + glNewList( floor_list, GL_COMPILE_AND_EXECUTE ); + + // Set floor material + glMaterialfv( GL_FRONT, GL_DIFFUSE, floor_diffuse ); + glMaterialfv( GL_FRONT, GL_SPECULAR, floor_specular ); + glMaterialf( GL_FRONT, GL_SHININESS, floor_shininess ); + + // Draw floor as a bunch of triangle strips (high tesselation + // improves lighting) + glNormal3f( 0.0f, 0.0f, 1.0f ); + glBegin( GL_QUADS ); + TesselateFloor( -1.0f,-1.0f, 0.0f,0.0f, 0 ); + TesselateFloor( 0.0f,-1.0f, 1.0f,0.0f, 0 ); + TesselateFloor( 0.0f, 0.0f, 1.0f,1.0f, 0 ); + TesselateFloor( -1.0f, 0.0f, 0.0f,1.0f, 0 ); + glEnd(); + + // End recording of display list + glEndList(); + } + else + { + // Playback display list + glCallList( floor_list ); + } + + glDisable( GL_TEXTURE_2D ); + +} + + +//======================================================================== +// SetupLights() - Position and configure light sources +//======================================================================== + +void SetupLights( void ) +{ + float l1pos[4], l1amb[4], l1dif[4], l1spec[4]; + float l2pos[4], l2amb[4], l2dif[4], l2spec[4]; + + // Set light source 1 parameters + l1pos[0] = 0.0f; l1pos[1] = -9.0f; l1pos[2] = 8.0f; l1pos[3] = 1.0f; + l1amb[0] = 0.2f; l1amb[1] = 0.2f; l1amb[2] = 0.2f; l1amb[3] = 1.0f; + l1dif[0] = 0.8f; l1dif[1] = 0.4f; l1dif[2] = 0.2f; l1dif[3] = 1.0f; + l1spec[0] = 1.0f; l1spec[1] = 0.6f; l1spec[2] = 0.2f; l1spec[3] = 0.0f; + + // Set light source 2 parameters + l2pos[0] = -15.0f; l2pos[1] = 12.0f; l2pos[2] = 1.5f; l2pos[3] = 1.0f; + l2amb[0] = 0.0f; l2amb[1] = 0.0f; l2amb[2] = 0.0f; l2amb[3] = 1.0f; + l2dif[0] = 0.2f; l2dif[1] = 0.4f; l2dif[2] = 0.8f; l2dif[3] = 1.0f; + l2spec[0] = 0.2f; l2spec[1] = 0.6f; l2spec[2] = 1.0f; l2spec[3] = 0.0f; + + // Configure light sources in OpenGL + glLightfv( GL_LIGHT1, GL_POSITION, l1pos ); + glLightfv( GL_LIGHT1, GL_AMBIENT, l1amb ); + glLightfv( GL_LIGHT1, GL_DIFFUSE, l1dif ); + glLightfv( GL_LIGHT1, GL_SPECULAR, l1spec ); + glLightfv( GL_LIGHT2, GL_POSITION, l2pos ); + glLightfv( GL_LIGHT2, GL_AMBIENT, l2amb ); + glLightfv( GL_LIGHT2, GL_DIFFUSE, l2dif ); + glLightfv( GL_LIGHT2, GL_SPECULAR, l2spec ); + glLightfv( GL_LIGHT3, GL_POSITION, glow_pos ); + glLightfv( GL_LIGHT3, GL_DIFFUSE, glow_color ); + glLightfv( GL_LIGHT3, GL_SPECULAR, glow_color ); + + // Enable light sources + glEnable( GL_LIGHT1 ); + glEnable( GL_LIGHT2 ); + glEnable( GL_LIGHT3 ); +} + + +//======================================================================== +// Draw() - Main rendering function +//======================================================================== + +void Draw( double t ) +{ + double xpos, ypos, zpos, angle_x, angle_y, angle_z; + static double t_old = 0.0; + float dt; + + // Calculate frame-to-frame delta time + dt = (float)(t-t_old); + t_old = t; + + // Setup viewport + glViewport( 0, 0, width, height ); + + // Clear color and Z-buffer + glClearColor( 0.1f, 0.1f, 0.1f, 1.0f ); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + // Setup projection + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( 65.0, (double)width/(double)height, 1.0, 60.0 ); + + // Setup camera + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + // Rotate camera + angle_x = 90.0 - 10.0; + angle_y = 10.0 * sin( 0.3 * t ); + angle_z = 10.0 * t; + glRotated( -angle_x, 1.0, 0.0, 0.0 ); + glRotated( -angle_y, 0.0, 1.0, 0.0 ); + glRotated( -angle_z, 0.0, 0.0, 1.0 ); + + // Translate camera + xpos = 15.0 * sin( (M_PI/180.0) * angle_z ) + + 2.0 * sin( (M_PI/180.0) * 3.1 * t ); + ypos = -15.0 * cos( (M_PI/180.0) * angle_z ) + + 2.0 * cos( (M_PI/180.0) * 2.9 * t ); + zpos = 4.0 + 2.0 * cos( (M_PI/180.0) * 4.9 * t ); + glTranslated( -xpos, -ypos, -zpos ); + + // Enable face culling + glFrontFace( GL_CCW ); + glCullFace( GL_BACK ); + glEnable( GL_CULL_FACE ); + + // Enable lighting + SetupLights(); + glEnable( GL_LIGHTING ); + + // Enable fog (dim details far away) + glEnable( GL_FOG ); + glFogi( GL_FOG_MODE, GL_EXP ); + glFogf( GL_FOG_DENSITY, 0.05f ); + glFogfv( GL_FOG_COLOR, fog_color ); + + // Draw floor + DrawFloor(); + + // Enable Z-buffering + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_LEQUAL ); + glDepthMask( GL_TRUE ); + + // Draw fountain + DrawFountain(); + + // Disable fog & lighting + glDisable( GL_LIGHTING ); + glDisable( GL_FOG ); + + // Draw all particles (must be drawn after all solid objects have been + // drawn!) + DrawParticles( t, dt ); + + // Z-buffer not needed anymore + glDisable( GL_DEPTH_TEST ); +} + + +//======================================================================== +// Resize() - GLFW window resize callback function +//======================================================================== + +void GLFWCALL Resize( int x, int y ) +{ + width = x; + height = y > 0 ? y : 1; // Prevent division by zero in aspect calc. +} + + +//======================================================================== +// Input callback functions +//======================================================================== + +void GLFWCALL KeyFun( int key, int action ) +{ + if( action == GLFW_PRESS ) + { + switch( key ) + { + case GLFW_KEY_ESC: + running = 0; + break; + case 'W': + wireframe = !wireframe; + glPolygonMode( GL_FRONT_AND_BACK, + wireframe ? GL_LINE : GL_FILL ); + break; + default: + break; + } + } +} + + +//======================================================================== +// PhysicsThreadFun() - Thread for updating particle physics +//======================================================================== + +void GLFWCALL PhysicsThreadFun( void *arg ) +{ + while( running ) + { + // Lock mutex + glfwLockMutex( thread_sync.particles_lock ); + + // Wait for particle drawing to be done + while( running && thread_sync.p_frame > thread_sync.d_frame ) + { + glfwWaitCond( thread_sync.d_done, thread_sync.particles_lock, + 0.1 ); + } + + // No longer running? + if( !running ) + { + break; + } + + // Update particles + ParticleEngine( thread_sync.t, thread_sync.dt ); + + // Update frame counter + thread_sync.p_frame ++; + + // Unlock mutex and signal drawing thread + glfwUnlockMutex( thread_sync.particles_lock ); + glfwSignalCond( thread_sync.p_done ); + } +} + + +//======================================================================== +// main() +//======================================================================== + +int main( int argc, char **argv ) +{ + int i, frames, benchmark; + double t0, t; + GLFWthread physics_thread = 0; + + // Use multithreading by default, but don't benchmark + multithreading = 1; + benchmark = 0; + + // Check command line arguments + for( i = 1; i < argc; i ++ ) + { + // Use benchmarking? + if( strcmp( argv[i], "-b" ) == 0 ) + { + benchmark = 1; + } + + // Force multithreading off? + else if( strcmp( argv[i], "-s" ) == 0 ) + { + multithreading = 0; + } + + // With a Finder launch on Mac OS X we get a bogus -psn_0_46268417 + // kind of argument (actual numbers vary). Ignore it. + else if( strncmp( argv[i], "-psn_", 5) == 0 ); + + // Usage + else + { + if( strcmp( argv[i], "-?" ) != 0 ) + { + printf( "Unknonwn option %s\n\n", argv[ i ] ); + } + printf( "Usage: %s [options]\n", argv[ 0 ] ); + printf( "\n"); + printf( "Options:\n" ); + printf( " -b Benchmark (run program for 60 s)\n" ); + printf( " -s Run program as single thread (default is to use two threads)\n" ); + printf( " -? Display this text\n" ); + printf( "\n"); + printf( "Program runtime controls:\n" ); + printf( " w Toggle wireframe mode\n" ); + printf( " ESC Exit program\n" ); + exit( 0 ); + } + } + + // Initialize GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + // Open OpenGL fullscreen window + if( !glfwOpenWindow( WIDTH, HEIGHT, 0,0,0,0, 16,0, GLFW_FULLSCREEN ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + // Set window title + glfwSetWindowTitle( "Particle engine" ); + + // Disable VSync (we want to get as high FPS as possible!) + glfwSwapInterval( 0 ); + + // Window resize callback function + glfwSetWindowSizeCallback( Resize ); + + // Set keyboard input callback function + glfwSetKeyCallback( KeyFun ); + + // Upload particle texture + glGenTextures( 1, &particle_tex_id ); + glBindTexture( GL_TEXTURE_2D, particle_tex_id ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, P_TEX_WIDTH, P_TEX_HEIGHT, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, particle_texture ); + + // Upload floor texture + glGenTextures( 1, &floor_tex_id ); + glBindTexture( GL_TEXTURE_2D, floor_tex_id ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, F_TEX_WIDTH, F_TEX_HEIGHT, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, floor_texture ); + + // Check if we have GL_EXT_separate_specular_color, and if so use it + if( glfwExtensionSupported( "GL_EXT_separate_specular_color" ) ) + { + glLightModeli( GL_LIGHT_MODEL_COLOR_CONTROL_EXT, + GL_SEPARATE_SPECULAR_COLOR_EXT ); + } + + // Set filled polygon mode as default (not wireframe) + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + wireframe = 0; + + // Clear particle system + for( i = 0; i < MAX_PARTICLES; i ++ ) + { + particles[ i ].active = 0; + } + min_age = 0.0f; + + // Set "running" flag + running = 1; + + // Set initial times + thread_sync.t = 0.0; + thread_sync.dt = 0.001f; + + // Init threading + if( multithreading ) + { + thread_sync.p_frame = 0; + thread_sync.d_frame = 0; + thread_sync.particles_lock = glfwCreateMutex(); + thread_sync.p_done = glfwCreateCond(); + thread_sync.d_done = glfwCreateCond(); + physics_thread = glfwCreateThread( PhysicsThreadFun, NULL ); + } + + // Main loop + t0 = glfwGetTime(); + frames = 0; + while( running ) + { + // Get frame time + t = glfwGetTime() - t0; + + // Draw... + Draw( t ); + + // Swap buffers + glfwSwapBuffers(); + + // Check if window was closed + running = running && glfwGetWindowParam( GLFW_OPENED ); + + // Increase frame count + frames ++; + + // End of benchmark? + if( benchmark && t >= 60.0 ) + { + running = 0; + } + } + t = glfwGetTime() - t0; + + // Wait for particle physics thread to die + if( multithreading ) + { + glfwWaitThread( physics_thread, GLFW_WAIT ); + } + + // Display profiling information + printf( "%d frames in %.2f seconds = %.1f FPS", frames, t, + (double)frames / t ); + printf( " (multithreading %s)\n", multithreading ? "on" : "off" ); + + // Terminate OpenGL + glfwTerminate(); + + exit( EXIT_SUCCESS ); +} + diff --git a/examples/pong3d.c b/examples/pong3d.c new file mode 100644 index 00000000..1d1afd1f --- /dev/null +++ b/examples/pong3d.c @@ -0,0 +1,854 @@ +//======================================================================== +// This is a small test application for GLFW. +// This is an OpenGL port of the famous "PONG" game (the first computer +// game ever?). It is very simple, and could be improved alot. It was +// created in order to show off the gaming capabilities of GLFW. +//======================================================================== + +#include +#include +#include +#include + + +//======================================================================== +// Constants +//======================================================================== + +// Screen resolution +#define WIDTH 640 +#define HEIGHT 480 + +// Player size (units) +#define PLAYER_XSIZE 0.05f +#define PLAYER_YSIZE 0.15f + +// Ball size (units) +#define BALL_SIZE 0.02f + +// Maximum player movement speed (units / second) +#define MAX_SPEED 1.5f + +// Player movement acceleration (units / seconds^2) +#define ACCELERATION 4.0f + +// Player movement deceleration (units / seconds^2) +#define DECELERATION 2.0f + +// Ball movement speed (units / second) +#define BALL_SPEED 0.4f + +// Menu options +#define MENU_NONE 0 +#define MENU_PLAY 1 +#define MENU_QUIT 2 + +// Game events +#define NOBODY_WINS 0 +#define PLAYER1_WINS 1 +#define PLAYER2_WINS 2 + +// Winner ID +#define NOBODY 0 +#define PLAYER1 1 +#define PLAYER2 2 + +// Camera positions +#define CAMERA_CLASSIC 0 +#define CAMERA_ABOVE 1 +#define CAMERA_SPECTATOR 2 +#define CAMERA_DEFAULT CAMERA_CLASSIC + + +//======================================================================== +// Textures +//======================================================================== + +#define TEX_TITLE 0 +#define TEX_MENU 1 +#define TEX_INSTR 2 +#define TEX_WINNER1 3 +#define TEX_WINNER2 4 +#define TEX_FIELD 5 +#define NUM_TEXTURES 6 + +// Texture names +char * tex_name[ NUM_TEXTURES ] = { + "pong3d_title.tga", + "pong3d_menu.tga", + "pong3d_instr.tga", + "pong3d_winner1.tga", + "pong3d_winner2.tga", + "pong3d_field.tga" +}; + +// OpenGL texture object IDs +GLuint tex_id[ NUM_TEXTURES ]; + + +//======================================================================== +// Global variables +//======================================================================== + +// Display information +int width, height; + +// Frame information +double thistime, oldtime, dt, starttime; + +// Camera information +int camerapos; + +// Player information +struct { + double ypos; // -1.0 to +1.0 + double yspeed; // -MAX_SPEED to +MAX_SPEED +} player1, player2; + +// Ball information +struct { + double xpos, ypos; + double xspeed, yspeed; +} ball; + +// And the winner is... +int winner; + +// Lighting configuration +const GLfloat env_ambient[4] = {1.0f,1.0f,1.0f,1.0f}; +const GLfloat light1_position[4] = {-3.0f,3.0f,2.0f,1.0f}; +const GLfloat light1_diffuse[4] = {1.0f,1.0f,1.0f,0.0f}; +const GLfloat light1_ambient[4] = {0.0f,0.0f,0.0f,0.0f}; + +// Object material properties +const GLfloat player1_diffuse[4] = {1.0f,0.3f,0.3f,1.0f}; +const GLfloat player1_ambient[4] = {0.3f,0.1f,0.0f,1.0f}; +const GLfloat player2_diffuse[4] = {0.3f,1.0f,0.3f,1.0f}; +const GLfloat player2_ambient[4] = {0.1f,0.3f,0.1f,1.0f}; +const GLfloat ball_diffuse[4] = {1.0f,1.0f,0.5f,1.0f}; +const GLfloat ball_ambient[4] = {0.3f,0.3f,0.1f,1.0f}; +const GLfloat border_diffuse[4] = {0.3f,0.3f,1.0f,1.0f}; +const GLfloat border_ambient[4] = {0.1f,0.1f,0.3f,1.0f}; +const GLfloat floor_diffuse[4] = {1.0f,1.0f,1.0f,1.0f}; +const GLfloat floor_ambient[4] = {0.3f,0.3f,0.3f,1.0f}; + + +//======================================================================== +// LoadTextures() - Load textures from disk and upload to OpenGL card +//======================================================================== + +GLboolean LoadTextures( void ) +{ + int i; + + // Generate texture objects + glGenTextures( NUM_TEXTURES, tex_id ); + + // Load textures + for( i = 0; i < NUM_TEXTURES; i ++ ) + { + // Select texture object + glBindTexture( GL_TEXTURE_2D, tex_id[ i ] ); + + // Set texture parameters + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + // Upload texture from file to texture memory + if( !glfwLoadTexture2D( tex_name[ i ], 0 ) ) + { + fprintf( stderr, "Failed to load texture %s\n", tex_name[ i ] ); + return GL_FALSE; + } + } + + return GL_TRUE; +} + + +//======================================================================== +// DrawImage() - Draw a 2D image as a texture +//======================================================================== + +void DrawImage( int texnum, float x1, float x2, float y1, float y2 ) +{ + glEnable( GL_TEXTURE_2D ); + glBindTexture( GL_TEXTURE_2D, tex_id[ texnum ] ); + glBegin( GL_QUADS ); + glTexCoord2f( 0.0f, 1.0f ); + glVertex2f( x1, y1 ); + glTexCoord2f( 1.0f, 1.0f ); + glVertex2f( x2, y1 ); + glTexCoord2f( 1.0f, 0.0f ); + glVertex2f( x2, y2 ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex2f( x1, y2 ); + glEnd(); + glDisable( GL_TEXTURE_2D ); +} + + +//======================================================================== +// GameMenu() - Game menu (returns menu option) +//======================================================================== + +int GameMenu( void ) +{ + int option; + + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Wait for a game menu key to be pressed + do + { + // Get window size + glfwGetWindowSize( &width, &height ); + + // Set viewport + glViewport( 0, 0, width, height ); + + // Clear display + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); + glClear( GL_COLOR_BUFFER_BIT ); + + // Setup projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f ); + + // Setup modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + // Display title + glColor3f( 1.0f, 1.0f, 1.0f ); + DrawImage( TEX_TITLE, 0.1f, 0.9f, 0.0f, 0.3f ); + + // Display menu + glColor3f( 1.0f, 1.0f, 0.0f ); + DrawImage( TEX_MENU, 0.38f, 0.62f, 0.35f, 0.5f ); + + // Display instructions + glColor3f( 0.0f, 1.0f, 1.0f ); + DrawImage( TEX_INSTR, 0.32f, 0.68f, 0.65f, 0.85f ); + + // Swap buffers + glfwSwapBuffers(); + + // Check for keys + if( glfwGetKey( 'Q' ) || !glfwGetWindowParam( GLFW_OPENED ) ) + { + option = MENU_QUIT; + } + else if( glfwGetKey( GLFW_KEY_F1 ) ) + { + option = MENU_PLAY; + } + else + { + option = MENU_NONE; + } + + // To avoid horrible busy waiting, sleep for at least 20 ms + glfwSleep( 0.02 ); + } + while( option == MENU_NONE ); + + // Disable sticky keys + glfwDisable( GLFW_STICKY_KEYS ); + + return option; +} + + +//======================================================================== +// NewGame() - Initialize a new game +//======================================================================== + +void NewGame( void ) +{ + // Frame information + starttime = thistime = glfwGetTime(); + + // Camera information + camerapos = CAMERA_DEFAULT; + + // Player 1 information + player1.ypos = 0.0; + player1.yspeed = 0.0; + + // Player 2 information + player2.ypos = 0.0; + player2.yspeed = 0.0; + + // Ball information + ball.xpos = -1.0 + PLAYER_XSIZE; + ball.ypos = player1.ypos; + ball.xspeed = 1.0; + ball.yspeed = 1.0; +} + + +//======================================================================== +// PlayerControl() - Player control +//======================================================================== + +void PlayerControl( void ) +{ + float joy1pos[ 2 ], joy2pos[ 2 ]; + + // Get joystick X & Y axis positions + glfwGetJoystickPos( GLFW_JOYSTICK_1, joy1pos, 2 ); + glfwGetJoystickPos( GLFW_JOYSTICK_2, joy2pos, 2 ); + + // Player 1 control + if( glfwGetKey( 'A' ) || joy1pos[ 1 ] > 0.2f ) + { + player1.yspeed += dt * ACCELERATION; + if( player1.yspeed > MAX_SPEED ) + { + player1.yspeed = MAX_SPEED; + } + } + else if( glfwGetKey( 'Z' ) || joy1pos[ 1 ] < -0.2f ) + { + player1.yspeed -= dt * ACCELERATION; + if( player1.yspeed < -MAX_SPEED ) + { + player1.yspeed = -MAX_SPEED; + } + } + else + { + player1.yspeed /= exp( DECELERATION * dt ); + } + + // Player 2 control + if( glfwGetKey( 'K' ) || joy2pos[ 1 ] > 0.2f ) + { + player2.yspeed += dt * ACCELERATION; + if( player2.yspeed > MAX_SPEED ) + { + player2.yspeed = MAX_SPEED; + } + } + else if( glfwGetKey( 'M' ) || joy2pos[ 1 ] < -0.2f ) + { + player2.yspeed -= dt * ACCELERATION; + if( player2.yspeed < -MAX_SPEED ) + { + player2.yspeed = -MAX_SPEED; + } + } + else + { + player2.yspeed /= exp( DECELERATION * dt ); + } + + // Update player 1 position + player1.ypos += dt * player1.yspeed; + if( player1.ypos > 1.0 - PLAYER_YSIZE ) + { + player1.ypos = 1.0 - PLAYER_YSIZE; + player1.yspeed = 0.0; + } + else if( player1.ypos < -1.0 + PLAYER_YSIZE ) + { + player1.ypos = -1.0 + PLAYER_YSIZE; + player1.yspeed = 0.0; + } + + // Update player 2 position + player2.ypos += dt * player2.yspeed; + if( player2.ypos > 1.0 - PLAYER_YSIZE ) + { + player2.ypos = 1.0 - PLAYER_YSIZE; + player2.yspeed = 0.0; + } + else if( player2.ypos < -1.0 + PLAYER_YSIZE ) + { + player2.ypos = -1.0 + PLAYER_YSIZE; + player2.yspeed = 0.0; + } +} + + +//======================================================================== +// BallControl() - Ball control +//======================================================================== + +int BallControl( void ) +{ + int event; + double ballspeed; + + // Calculate new ball speed + ballspeed = BALL_SPEED * (1.0 + 0.02*(thistime-starttime)); + ball.xspeed = ball.xspeed > 0 ? ballspeed : -ballspeed; + ball.yspeed = ball.yspeed > 0 ? ballspeed : -ballspeed; + ball.yspeed *= 0.74321; + + // Update ball position + ball.xpos += dt * ball.xspeed; + ball.ypos += dt * ball.yspeed; + + // Did the ball hit a top/bottom wall? + if( ball.ypos >= 1.0 ) + { + ball.ypos = 2.0 - ball.ypos; + ball.yspeed = -ball.yspeed; + } + else if( ball.ypos <= -1.0 ) + { + ball.ypos = -2.0 - ball.ypos; + ball.yspeed = -ball.yspeed; + } + + // Did the ball hit/miss a player? + event = NOBODY_WINS; + + // Is the ball entering the player 1 goal? + if( ball.xpos < -1.0 + PLAYER_XSIZE ) + { + // Did player 1 catch the ball? + if( ball.ypos > (player1.ypos-PLAYER_YSIZE) && + ball.ypos < (player1.ypos+PLAYER_YSIZE) ) + { + ball.xpos = -2.0 + 2.0*PLAYER_XSIZE - ball.xpos; + ball.xspeed = -ball.xspeed; + } + else + { + event = PLAYER2_WINS; + } + } + + // Is the ball entering the player 2 goal? + if( ball.xpos > 1.0 - PLAYER_XSIZE ) + { + // Did player 2 catch the ball? + if( ball.ypos > (player2.ypos-PLAYER_YSIZE) && + ball.ypos < (player2.ypos+PLAYER_YSIZE) ) + { + ball.xpos = 2.0 - 2.0*PLAYER_XSIZE - ball.xpos; + ball.xspeed = -ball.xspeed; + } + else + { + event = PLAYER1_WINS; + } + } + + return event; +} + + +//======================================================================== +// DrawBox() - Draw a 3D box +//======================================================================== + +#define TEX_SCALE 4.0f + + +void DrawBox( float x1, float y1, float z1, float x2, float y2, float z2 ) +{ + // Draw six sides of a cube + glBegin( GL_QUADS ); + // Side 1 (down) + glNormal3f( 0.0f, 0.0f, -1.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x1,y2,z1 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x2,y2,z1 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x2,y1,z1 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x1,y1,z1 ); + // Side 2 (up) + glNormal3f( 0.0f, 0.0f, 1.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x1,y1,z2 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x2,y1,z2 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x2,y2,z2 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x1,y2,z2 ); + // Side 3 (backward) + glNormal3f( 0.0f, -1.0f, 0.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x1,y1,z1 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x2,y1,z1 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x2,y1,z2 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x1,y1,z2 ); + // Side 4 (forward) + glNormal3f( 0.0f, 1.0f, 0.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x1,y2,z2 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x2,y2,z2 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x2,y2,z1 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x1,y2,z1 ); + // Side 5 (left) + glNormal3f( -1.0f, 0.0f, 0.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x1,y1,z2 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x1,y2,z2 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x1,y2,z1 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x1,y1,z1 ); + // Side 6 (right) + glNormal3f( 1.0f, 0.0f, 0.0f ); + glTexCoord2f( 0.0f, 0.0f ); + glVertex3f( x2,y1,z1 ); + glTexCoord2f( TEX_SCALE, 0.0f ); + glVertex3f( x2,y2,z1 ); + glTexCoord2f( TEX_SCALE, TEX_SCALE ); + glVertex3f( x2,y2,z2 ); + glTexCoord2f( 0.0f, TEX_SCALE ); + glVertex3f( x2,y1,z2 ); + glEnd(); +} + + +//======================================================================== +// UpdateDisplay() - Draw graphics (all game related OpenGL stuff goes +// here) +//======================================================================== + +void UpdateDisplay( void ) +{ + // Get window size + glfwGetWindowSize( &width, &height ); + + // Set viewport + glViewport( 0, 0, width, height ); + + // Clear display + glClearColor( 0.02f, 0.02f, 0.02f, 0.0f ); + glClearDepth( 1.0f ); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + // Setup projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( + 55.0f, // Angle of view + (GLfloat)width/(GLfloat)height, // Aspect + 1.0f, // Near Z + 100.0f // Far Z + ); + + // Setup modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + switch( camerapos ) + { + default: + case CAMERA_CLASSIC: + gluLookAt( + 0.0f, 0.0f, 2.5f, + 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f + ); + break; + case CAMERA_ABOVE: + gluLookAt( + 0.0f, 0.0f, 2.5f, + (float)ball.xpos, (float)ball.ypos, 0.0f, + 0.0f, 1.0f, 0.0f + ); + break; + case CAMERA_SPECTATOR: + gluLookAt( + 0.0f, -2.0, 1.2f, + (float)ball.xpos, (float)ball.ypos, 0.0f, + 0.0f, 0.0f, 1.0f + ); + break; + } + + // Enable depth testing + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_LEQUAL ); + + // Enable lighting + glEnable( GL_LIGHTING ); + glLightModelfv( GL_LIGHT_MODEL_AMBIENT, env_ambient ); + glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE ); + glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE ); + glLightfv( GL_LIGHT1, GL_POSITION, light1_position ); + glLightfv( GL_LIGHT1, GL_DIFFUSE, light1_diffuse ); + glLightfv( GL_LIGHT1, GL_AMBIENT, light1_ambient ); + glEnable( GL_LIGHT1 ); + + // Front face is counter-clock-wise + glFrontFace( GL_CCW ); + + // Enable face culling (not necessary, but speeds up rendering) + glCullFace( GL_BACK ); + glEnable( GL_CULL_FACE ); + + // Draw Player 1 + glMaterialfv( GL_FRONT, GL_DIFFUSE, player1_diffuse ); + glMaterialfv( GL_FRONT, GL_AMBIENT, player1_ambient ); + DrawBox( -1.f, (GLfloat)player1.ypos-PLAYER_YSIZE, 0.f, + -1.f+PLAYER_XSIZE, (GLfloat)player1.ypos+PLAYER_YSIZE, 0.1f ); + + // Draw Player 2 + glMaterialfv( GL_FRONT, GL_DIFFUSE, player2_diffuse ); + glMaterialfv( GL_FRONT, GL_AMBIENT, player2_ambient ); + DrawBox( 1.f-PLAYER_XSIZE, (GLfloat)player2.ypos-PLAYER_YSIZE, 0.f, + 1.f, (GLfloat)player2.ypos+PLAYER_YSIZE, 0.1f ); + + // Draw Ball + glMaterialfv( GL_FRONT, GL_DIFFUSE, ball_diffuse ); + glMaterialfv( GL_FRONT, GL_AMBIENT, ball_ambient ); + DrawBox( (GLfloat)ball.xpos-BALL_SIZE, (GLfloat)ball.ypos-BALL_SIZE, 0.f, + (GLfloat)ball.xpos+BALL_SIZE, (GLfloat)ball.ypos+BALL_SIZE, BALL_SIZE*2 ); + + // Top game field border + glMaterialfv( GL_FRONT, GL_DIFFUSE, border_diffuse ); + glMaterialfv( GL_FRONT, GL_AMBIENT, border_ambient ); + DrawBox( -1.1f, 1.0f, 0.0f, 1.1f, 1.1f, 0.1f ); + // Bottom game field border + glColor3f( 0.0f, 0.0f, 0.7f ); + DrawBox( -1.1f, -1.1f, 0.0f, 1.1f, -1.0f, 0.1f ); + // Left game field border + DrawBox( -1.1f, -1.0f, 0.0f, -1.0f, 1.0f, 0.1f ); + // Left game field border + DrawBox( 1.0f, -1.0f, 0.0f, 1.1f, 1.0f, 0.1f ); + + // Enable texturing + glEnable( GL_TEXTURE_2D ); + glBindTexture( GL_TEXTURE_2D, tex_id[ TEX_FIELD ] ); + + // Game field floor + glMaterialfv( GL_FRONT, GL_DIFFUSE, floor_diffuse ); + glMaterialfv( GL_FRONT, GL_AMBIENT, floor_ambient ); + DrawBox( -1.01f, -1.01f, -0.01f, 1.01f, 1.01f, 0.0f ); + + // Disable texturing + glDisable( GL_TEXTURE_2D ); + + // Disable face culling + glDisable( GL_CULL_FACE ); + + // Disable lighting + glDisable( GL_LIGHTING ); + + // Disable depth testing + glDisable( GL_DEPTH_TEST ); +} + + +//======================================================================== +// GameOver() +//======================================================================== + +void GameOver( void ) +{ + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Until the user presses ESC or SPACE + while( !glfwGetKey( GLFW_KEY_ESC ) && !glfwGetKey( ' ' ) && + glfwGetWindowParam( GLFW_OPENED ) ) + { + // Draw display + UpdateDisplay(); + + // Setup projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f ); + + // Setup modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + // Enable blending + glEnable( GL_BLEND ); + + // Dim background + glBlendFunc( GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA ); + glColor4f( 0.3f, 0.3f, 0.3f, 0.3f ); + glBegin( GL_QUADS ); + glVertex2f( 0.0f, 0.0f ); + glVertex2f( 1.0f, 0.0f ); + glVertex2f( 1.0f, 1.0f ); + glVertex2f( 0.0f, 1.0f ); + glEnd(); + + // Display winner text + glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_COLOR ); + if( winner == PLAYER1 ) + { + glColor4f( 1.0f, 0.5f, 0.5f, 1.0f ); + DrawImage( TEX_WINNER1, 0.35f, 0.65f, 0.46f, 0.54f ); + } + else if( winner == PLAYER2 ) + { + glColor4f( 0.5f, 1.0f, 0.5f, 1.0f ); + DrawImage( TEX_WINNER2, 0.35f, 0.65f, 0.46f, 0.54f ); + } + + // Disable blending + glDisable( GL_BLEND ); + + // Swap buffers + glfwSwapBuffers(); + } + + // Disable sticky keys + glfwDisable( GLFW_STICKY_KEYS ); +} + + +//======================================================================== +// GameLoop() - Game loop +//======================================================================== + +void GameLoop( void ) +{ + int playing, event; + + // Initialize a new game + NewGame(); + + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Loop until the game ends + playing = GL_TRUE; + while( playing && glfwGetWindowParam( GLFW_OPENED ) ) + { + // Frame timer + oldtime = thistime; + thistime = glfwGetTime(); + dt = thistime - oldtime; + + // Get user input and update player positions + PlayerControl(); + + // Move the ball, and check if a player hits/misses the ball + event = BallControl(); + + // Did we have a winner? + switch( event ) + { + case PLAYER1_WINS: + winner = PLAYER1; + playing = GL_FALSE; + break; + case PLAYER2_WINS: + winner = PLAYER2; + playing = GL_FALSE; + break; + default: + break; + } + + // Did the user press ESC? + if( glfwGetKey( GLFW_KEY_ESC ) ) + { + playing = GL_FALSE; + } + + // Did the user change camera view? + if( glfwGetKey( '1' ) ) + { + camerapos = CAMERA_CLASSIC; + } + else if( glfwGetKey( '2' ) ) + { + camerapos = CAMERA_ABOVE; + } + else if( glfwGetKey( '3' ) ) + { + camerapos = CAMERA_SPECTATOR; + } + + // Draw display + UpdateDisplay(); + + // Swap buffers + glfwSwapBuffers(); + } + + // Disable sticky keys + glfwDisable( GLFW_STICKY_KEYS ); + + // Show winner + GameOver(); +} + + +//======================================================================== +// main() - Program entry point +//======================================================================== + +int main( void ) +{ + int menuoption; + + // Initialize GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + // Open OpenGL window + if( !glfwOpenWindow( WIDTH, HEIGHT, 0,0,0,0, 16,0, GLFW_FULLSCREEN ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + glfwSwapInterval( 1 ); + + // Load all textures + if( !LoadTextures() ) + { + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + // Main loop + do + { + // Get menu option + menuoption = GameMenu(); + + // If the user wants to play, let him... + if( menuoption == MENU_PLAY ) + { + GameLoop(); + } + } + while( menuoption != MENU_QUIT ); + + // Unload all textures + if( glfwGetWindowParam( GLFW_OPENED ) ) + { + glDeleteTextures( NUM_TEXTURES, tex_id ); + } + + // Terminate GLFW + glfwTerminate(); + + exit( EXIT_SUCCESS ); +} + diff --git a/examples/pong3d_field.tga b/examples/pong3d_field.tga new file mode 100644 index 00000000..cc20bbdb Binary files /dev/null and b/examples/pong3d_field.tga differ diff --git a/examples/pong3d_instr.tga b/examples/pong3d_instr.tga new file mode 100644 index 00000000..758eb447 Binary files /dev/null and b/examples/pong3d_instr.tga differ diff --git a/examples/pong3d_menu.tga b/examples/pong3d_menu.tga new file mode 100644 index 00000000..d0d6c5a4 Binary files /dev/null and b/examples/pong3d_menu.tga differ diff --git a/examples/pong3d_title.tga b/examples/pong3d_title.tga new file mode 100644 index 00000000..d0d8e36d Binary files /dev/null and b/examples/pong3d_title.tga differ diff --git a/examples/pong3d_winner1.tga b/examples/pong3d_winner1.tga new file mode 100644 index 00000000..f963720c Binary files /dev/null and b/examples/pong3d_winner1.tga differ diff --git a/examples/pong3d_winner2.tga b/examples/pong3d_winner2.tga new file mode 100644 index 00000000..ea8266de Binary files /dev/null and b/examples/pong3d_winner2.tga differ diff --git a/examples/splitview.c b/examples/splitview.c new file mode 100644 index 00000000..a26cd2c5 --- /dev/null +++ b/examples/splitview.c @@ -0,0 +1,514 @@ +//======================================================================== +// This is an example program for the GLFW library +// +// The program uses a "split window" view, rendering four views of the +// same scene in one window (e.g. uesful for 3D modelling software). This +// demo uses scissors to separete the four different rendering areas from +// each other. +// +// (If the code seems a little bit strange here and there, it may be +// because I am not a friend of orthogonal projections) +//======================================================================== + +#include +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +//======================================================================== +// Global variables +//======================================================================== + +// Mouse position +static int xpos = 0, ypos = 0; + +// Window size +static int width, height; + +// Active view: 0 = none, 1 = upper left, 2 = upper right, 3 = lower left, +// 4 = lower right +static int active_view = 0; + +// Rotation around each axis +static int rot_x = 0, rot_y = 0, rot_z = 0; + +// Do redraw? +static int do_redraw = 1; + + +//======================================================================== +// Draw a solid torus (use a display list for the model) +//======================================================================== + +#define TORUS_MAJOR 1.5 +#define TORUS_MINOR 0.5 +#define TORUS_MAJOR_RES 32 +#define TORUS_MINOR_RES 32 + +static void drawTorus( void ) +{ + static GLuint torus_list = 0; + int i, j, k; + double s, t, x, y, z, nx, ny, nz, scale, twopi; + + if( !torus_list ) + { + // Start recording displaylist + torus_list = glGenLists( 1 ); + glNewList( torus_list, GL_COMPILE_AND_EXECUTE ); + + // Draw torus + twopi = 2.0 * M_PI; + for( i = 0; i < TORUS_MINOR_RES; i++ ) + { + glBegin( GL_QUAD_STRIP ); + for( j = 0; j <= TORUS_MAJOR_RES; j++ ) + { + for( k = 1; k >= 0; k-- ) + { + s = (i + k) % TORUS_MINOR_RES + 0.5; + t = j % TORUS_MAJOR_RES; + + // Calculate point on surface + x = (TORUS_MAJOR+TORUS_MINOR*cos(s*twopi/TORUS_MINOR_RES))*cos(t*twopi/TORUS_MAJOR_RES); + y = TORUS_MINOR * sin(s * twopi / TORUS_MINOR_RES); + z = (TORUS_MAJOR+TORUS_MINOR*cos(s*twopi/TORUS_MINOR_RES))*sin(t*twopi/TORUS_MAJOR_RES); + + // Calculate surface normal + nx = x - TORUS_MAJOR*cos(t*twopi/TORUS_MAJOR_RES); + ny = y; + nz = z - TORUS_MAJOR*sin(t*twopi/TORUS_MAJOR_RES); + scale = 1.0 / sqrt( nx*nx + ny*ny + nz*nz ); + nx *= scale; + ny *= scale; + nz *= scale; + + glNormal3f( (float)nx, (float)ny, (float)nz ); + glVertex3f( (float)x, (float)y, (float)z ); + } + } + glEnd(); + } + + // Stop recording displaylist + glEndList(); + } + else + { + // Playback displaylist + glCallList( torus_list ); + } +} + + +//======================================================================== +// Draw the scene (a rotating torus) +//======================================================================== + +static void drawScene( void ) +{ + const GLfloat model_diffuse[4] = {1.0f, 0.8f, 0.8f, 1.0f}; + const GLfloat model_specular[4] = {0.6f, 0.6f, 0.6f, 1.0f}; + const GLfloat model_shininess = 20.0f; + + glPushMatrix(); + + // Rotate the object + glRotatef( (GLfloat)rot_x*0.5f, 1.0f, 0.0f, 0.0f ); + glRotatef( (GLfloat)rot_y*0.5f, 0.0f, 1.0f, 0.0f ); + glRotatef( (GLfloat)rot_z*0.5f, 0.0f, 0.0f, 1.0f ); + + // Set model color (used for orthogonal views, lighting disabled) + glColor4fv( model_diffuse ); + + // Set model material (used for perspective view, lighting enabled) + glMaterialfv( GL_FRONT, GL_DIFFUSE, model_diffuse ); + glMaterialfv( GL_FRONT, GL_SPECULAR, model_specular ); + glMaterialf( GL_FRONT, GL_SHININESS, model_shininess ); + + // Draw torus + drawTorus(); + + glPopMatrix(); +} + + +//======================================================================== +// Draw a 2D grid (used for orthogonal views) +//======================================================================== + +static void drawGrid( float scale, int steps ) +{ + int i; + float x, y; + + glPushMatrix(); + + // Set background to some dark bluish grey + glClearColor( 0.05f, 0.05f, 0.2f, 0.0f); + glClear( GL_COLOR_BUFFER_BIT ); + + // Setup modelview matrix (flat XY view) + glLoadIdentity(); + gluLookAt( 0.0, 0.0, 1.0, + 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0 ); + + // We don't want to update the Z-buffer + glDepthMask( GL_FALSE ); + + // Set grid color + glColor3f( 0.0f, 0.5f, 0.5f ); + + glBegin( GL_LINES ); + + // Horizontal lines + x = scale * 0.5f * (float)(steps-1); + y = -scale * 0.5f * (float)(steps-1); + for( i = 0; i < steps; i ++ ) + { + glVertex3f( -x, y, 0.0f ); + glVertex3f( x, y, 0.0f ); + y += scale; + } + + // Vertical lines + x = -scale * 0.5f * (float)(steps-1); + y = scale * 0.5f * (float)(steps-1); + for( i = 0; i < steps; i ++ ) + { + glVertex3f( x, -y, 0.0f ); + glVertex3f( x, y, 0.0f ); + x += scale; + } + + glEnd(); + + // Enable Z-buffer writing again + glDepthMask( GL_TRUE ); + + glPopMatrix(); +} + + +//======================================================================== +// Draw all views +//======================================================================== + +static void drawAllViews( void ) +{ + const GLfloat light_position[4] = {0.0f, 8.0f, 8.0f, 1.0f}; + const GLfloat light_diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const GLfloat light_specular[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const GLfloat light_ambient[4] = {0.2f, 0.2f, 0.3f, 1.0f}; + double aspect; + + // Calculate aspect of window + if( height > 0 ) + { + aspect = (double)width / (double)height; + } + else + { + aspect = 1.0; + } + + // Clear screen + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + // Enable scissor test + glEnable( GL_SCISSOR_TEST ); + + // Enable depth test + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_LEQUAL ); + + + // ** ORTHOGONAL VIEWS ** + + // For orthogonal views, use wireframe rendering + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + + // Enable line anti-aliasing + glEnable( GL_LINE_SMOOTH ); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + + // Setup orthogonal projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( -3.0*aspect, 3.0*aspect, -3.0, 3.0, 1.0, 50.0 ); + + // Upper left view (TOP VIEW) + glViewport( 0, height/2, width/2, height/2 ); + glScissor( 0, height/2, width/2, height/2 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 0.0f, 10.0f, 1e-3f, // Eye-position (above) + 0.0f, 0.0f, 0.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + drawGrid( 0.5, 12 ); + drawScene(); + + // Lower left view (FRONT VIEW) + glViewport( 0, 0, width/2, height/2 ); + glScissor( 0, 0, width/2, height/2 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 0.0f, 0.0f, 10.0f, // Eye-position (in front of) + 0.0f, 0.0f, 0.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + drawGrid( 0.5, 12 ); + drawScene(); + + // Lower right view (SIDE VIEW) + glViewport( width/2, 0, width/2, height/2 ); + glScissor( width/2, 0, width/2, height/2 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 10.0f, 0.0f, 0.0f, // Eye-position (to the right) + 0.0f, 0.0f, 0.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + drawGrid( 0.5, 12 ); + drawScene(); + + // Disable line anti-aliasing + glDisable( GL_LINE_SMOOTH ); + glDisable( GL_BLEND ); + + + // ** PERSPECTIVE VIEW ** + + // For perspective view, use solid rendering + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + + // Enable face culling (faster rendering) + glEnable( GL_CULL_FACE ); + glCullFace( GL_BACK ); + glFrontFace( GL_CW ); + + // Setup perspective projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( 65.0f, aspect, 1.0f, 50.0f ); + + // Upper right view (PERSPECTIVE VIEW) + glViewport( width/2, height/2, width/2, height/2 ); + glScissor( width/2, height/2, width/2, height/2 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 3.0f, 1.5f, 3.0f, // Eye-position + 0.0f, 0.0f, 0.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + + // Configure and enable light source 1 + glLightfv( GL_LIGHT1, GL_POSITION, light_position ); + glLightfv( GL_LIGHT1, GL_AMBIENT, light_ambient ); + glLightfv( GL_LIGHT1, GL_DIFFUSE, light_diffuse ); + glLightfv( GL_LIGHT1, GL_SPECULAR, light_specular ); + glEnable( GL_LIGHT1 ); + glEnable( GL_LIGHTING ); + + // Draw scene + drawScene(); + + // Disable lighting + glDisable( GL_LIGHTING ); + + // Disable face culling + glDisable( GL_CULL_FACE ); + + // Disable depth test + glDisable( GL_DEPTH_TEST ); + + // Disable scissor test + glDisable( GL_SCISSOR_TEST ); + + + // Draw a border around the active view + if( active_view > 0 && active_view != 2 ) + { + glViewport( 0, 0, width, height ); + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( 0.0, 2.0, 0.0, 2.0, 0.0, 1.0 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + glColor3f( 1.0f, 1.0f, 0.6f ); + glTranslatef( (GLfloat) ((active_view - 1) & 1), (GLfloat) (1 - (active_view - 1) / 2), 0.0f ); + glBegin( GL_LINE_STRIP ); + glVertex2i( 0, 0 ); + glVertex2i( 1, 0 ); + glVertex2i( 1, 1 ); + glVertex2i( 0, 1 ); + glVertex2i( 0, 0 ); + glEnd(); + } +} + + +//======================================================================== +// Window size callback function +//======================================================================== + +static void windowSizeFun( int w, int h ) +{ + width = w; + height = h > 0 ? h : 1; + do_redraw = 1; +} + + +//======================================================================== +// Window refresh callback function +//======================================================================== + +static void windowRefreshFun( void ) +{ + do_redraw = 1; +} + + +//======================================================================== +// Mouse position callback function +//======================================================================== + +static void mousePosFun( int x, int y ) +{ + // Depending on which view was selected, rotate around different axes + switch( active_view ) + { + case 1: + rot_x += y - ypos; + rot_z += x - xpos; + do_redraw = 1; + break; + case 3: + rot_x += y - ypos; + rot_y += x - xpos; + do_redraw = 1; + break; + case 4: + rot_y += x - xpos; + rot_z += y - ypos; + do_redraw = 1; + break; + default: + // Do nothing for perspective view, or if no view is selected + break; + } + + // Remember mouse position + xpos = x; + ypos = y; +} + + +//======================================================================== +// Mouse button callback function +//======================================================================== + +static void mouseButtonFun( int button, int action ) +{ + // Button clicked? + if( ( button == GLFW_MOUSE_BUTTON_LEFT ) && action == GLFW_PRESS ) + { + // Detect which of the four views was clicked + active_view = 1; + if( xpos >= width/2 ) + { + active_view += 1; + } + if( ypos >= height/2 ) + { + active_view += 2; + } + } + + // Button released? + else if( button == GLFW_MOUSE_BUTTON_LEFT ) + { + // Deselect any previously selected view + active_view = 0; + } + + do_redraw = 1; +} + + +//======================================================================== +// main() +//======================================================================== + +int main( void ) +{ + // Initialise GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + // Open OpenGL window + if( !glfwOpenWindow( 500, 500, 0,0,0,0, 16,0, GLFW_WINDOW ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + // Enable vsync + glfwSwapInterval( 1 ); + + // Set window title + glfwSetWindowTitle( "Split view demo" ); + + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // Enable mouse cursor (only needed for fullscreen mode) + glfwEnable( GLFW_MOUSE_CURSOR ); + + // Disable automatic event polling + glfwDisable( GLFW_AUTO_POLL_EVENTS ); + + // Set callback functions + glfwSetWindowSizeCallback( windowSizeFun ); + glfwSetWindowRefreshCallback( windowRefreshFun ); + glfwSetMousePosCallback( mousePosFun ); + glfwSetMouseButtonCallback( mouseButtonFun ); + + // Main loop + do + { + // Only redraw if we need to + if( do_redraw ) + { + // Draw all views + drawAllViews(); + + // Swap buffers + glfwSwapBuffers(); + + do_redraw = 0; + } + + // Wait for new events + glfwWaitEvents(); + + } // Check if the ESC key was pressed or the window was closed + while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS && + glfwGetWindowParam( GLFW_OPENED ) ); + + // Close OpenGL window and terminate GLFW + glfwTerminate(); + + exit( EXIT_SUCCESS ); +} + diff --git a/examples/triangle.c b/examples/triangle.c new file mode 100644 index 00000000..a8b737be --- /dev/null +++ b/examples/triangle.c @@ -0,0 +1,94 @@ +//======================================================================== +// This is a small test application for GLFW. +// The program opens a window (640x480), and renders a spinning colored +// triangle (it is controlled with both the GLFW timer and the mouse). +//======================================================================== + +#include +#include +#include + + +int main( void ) +{ + int width, height, x; + double t; + + // Initialise GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + // Open a window and create its OpenGL context + if( !glfwOpenWindow( 640, 480, 0,0,0,0, 0,0, GLFW_WINDOW ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + glfwSetWindowTitle( "Spinning Triangle" ); + + // Ensure we can capture the escape key being pressed below + glfwEnable( GLFW_STICKY_KEYS ); + + // Enable vertical sync (on cards that support it) + glfwSwapInterval( 1 ); + + do + { + t = glfwGetTime(); + glfwGetMousePos( &x, NULL ); + + // Get window size (may be different than the requested size) + glfwGetWindowSize( &width, &height ); + + // Special case: avoid division by zero below + height = height > 0 ? height : 1; + + glViewport( 0, 0, width, height ); + + // Clear color buffer to black + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); + glClear( GL_COLOR_BUFFER_BIT ); + + // Select and setup the projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( 65.0f, (GLfloat)width/(GLfloat)height, 1.0f, 100.0f ); + + // Select and setup the modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 0.0f, 1.0f, 0.0f, // Eye-position + 0.0f, 20.0f, 0.0f, // View-point + 0.0f, 0.0f, 1.0f ); // Up-vector + + // Draw a rotating colorful triangle + glTranslatef( 0.0f, 14.0f, 0.0f ); + glRotatef( 0.3f*(GLfloat)x + (GLfloat)t*100.0f, 0.0f, 0.0f, 1.0f ); + glBegin( GL_TRIANGLES ); + glColor3f( 1.0f, 0.0f, 0.0f ); + glVertex3f( -5.0f, 0.0f, -4.0f ); + glColor3f( 0.0f, 1.0f, 0.0f ); + glVertex3f( 5.0f, 0.0f, -4.0f ); + glColor3f( 0.0f, 0.0f, 1.0f ); + glVertex3f( 0.0f, 0.0f, 6.0f ); + glEnd(); + + // Swap buffers + glfwSwapBuffers(); + + } // Check if the ESC key was pressed or the window was closed + while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS && + glfwGetWindowParam( GLFW_OPENED ) ); + + // Close OpenGL window and terminate GLFW + glfwTerminate(); + + exit( EXIT_SUCCESS ); +} + diff --git a/examples/wave.c b/examples/wave.c new file mode 100644 index 00000000..571cc9d5 --- /dev/null +++ b/examples/wave.c @@ -0,0 +1,399 @@ +/***************************************************************************** + * Wave Simulation in OpenGL + * (C) 2002 Jakob Thomsen + * http://home.in.tum.de/~thomsen + * Modified for GLFW by Sylvain Hellegouarch - sh@programmationworld.com + * Modified for variable frame rate by Marcus Geelnard + * 2003-Jan-31: Minor cleanups and speedups / MG + *****************************************************************************/ + +#include +#include +#include +#include + +#ifndef M_PI + #define M_PI 3.1415926535897932384626433832795 +#endif + +/* Maximum delta T to allow for differential calculations */ +#define MAX_DELTA_T 0.01 + +/* Animation speed (10.0 looks good) */ +#define ANIMATION_SPEED 10.0 + + +GLfloat alpha = 210.0f, beta = -70.0f; +GLfloat zoom = 2.0f; + +int running = 1; + +struct Vertex +{ + GLfloat x,y,z; + GLfloat r,g,b; +}; + +#define GRIDW 50 +#define GRIDH 50 +#define VERTEXNUM (GRIDW*GRIDH) + +#define QUADW (GRIDW-1) +#define QUADH (GRIDH-1) +#define QUADNUM (QUADW*QUADH) + +GLuint quad[4*QUADNUM]; +struct Vertex vertex[VERTEXNUM]; + +/* The grid will look like this: + * + * 3 4 5 + * *---*---* + * | | | + * | 0 | 1 | + * | | | + * *---*---* + * 0 1 2 + */ + +void initVertices( void ) +{ + int x,y,p; + + /* place the vertices in a grid */ + for(y=0;y1) zoom-=1; + break; + case GLFW_KEY_PAGEDOWN: + zoom+=1; + break; + default: + break; + } +} + + +/* Callback function for window resize events */ +void handle_resize( int width, int height ) +{ + float ratio = 1.0f; + + if( height > 0 ) + { + ratio = (float) width / (float) height; + } + + /* Setup viewport (Place where the stuff will appear in the main window). */ + glViewport(0, 0, width, height); + + /* + * Change to the projection matrix and set + * our viewing volume. + */ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(60.0, ratio, 1.0, 1024.0); +} + + +/* Program entry point */ +int main(int argc, char* argv[]) +{ + /* Dimensions of our window. */ + int width, height; + /* Style of our window. */ + int mode; + /* Frame time */ + double t, t_old, dt_total; + + /* Initialize GLFW */ + if(glfwInit() == GL_FALSE) + { + fprintf(stderr, "GLFW initialization failed\n"); + exit(-1); + } + + /* Desired window properties */ + width = 640; + height = 480; + mode = GLFW_WINDOW; + + /* Open window */ + if( glfwOpenWindow(width,height,0,0,0,0,16,0,mode) == GL_FALSE ) + { + fprintf(stderr, "Could not open window\n"); + glfwTerminate(); + exit(-1); + } + + /* Set title */ + glfwSetWindowTitle( "Wave Simulation" ); + + glfwSwapInterval( 1 ); + + /* Keyboard handler */ + glfwSetKeyCallback( handle_key_down ); + glfwEnable( GLFW_KEY_REPEAT ); + + /* Window resize handler */ + glfwSetWindowSizeCallback( handle_resize ); + + /* Initialize OpenGL */ + setup_opengl(); + + /* Initialize simulation */ + initVertices(); + initSurface(); + adjustGrid(); + + /* Initialize timer */ + t_old = glfwGetTime() - 0.01; + + /* Main loop */ + while(running) + { + /* Timing */ + t = glfwGetTime(); + dt_total = t - t_old; + t_old = t; + + /* Safety - iterate if dt_total is too large */ + while( dt_total > 0.0f ) + { + /* Select iteration time step */ + dt = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total; + dt_total -= dt; + + /* Calculate wave propagation */ + calc(); + } + + /* Compute height of each vertex */ + adjustGrid(); + + /* Draw wave grid to OpenGL display */ + draw_screen(); + + /* Still running? */ + running = running && glfwGetWindowParam( GLFW_OPENED ); + } + + glfwTerminate(); + + return 0; +} diff --git a/include/GL/glfw.h b/include/GL/glfw.h new file mode 100644 index 00000000..63313db3 --- /dev/null +++ b/include/GL/glfw.h @@ -0,0 +1,446 @@ +/************************************************************************ + * GLFW - An OpenGL framework + * API version: 2.7 + * WWW: http://www.glfw.org/ + *------------------------------------------------------------------------ + * Copyright (c) 2002-2006 Marcus Geelnard + * Copyright (c) 2006-2010 Camilla Berglund + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + *************************************************************************/ + +#ifndef __glfw_h_ +#define __glfw_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +/************************************************************************* + * Global definitions + *************************************************************************/ + +/* We need a NULL pointer from time to time */ +#ifndef NULL + #ifdef __cplusplus + #define NULL 0 + #else + #define NULL ((void *)0) + #endif +#endif /* NULL */ + + +/* ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- */ + +/* Please report any probles that you find with your compiler, which may + * be solved in this section! There are several compilers that I have not + * been able to test this file with yet. + * + * First: If we are we on Windows, we want a single define for it (_WIN32) + * (Note: For Cygwin the compiler flag -mwin32 should be used, but to + * make sure that things run smoothly for Cygwin users, we add __CYGWIN__ + * to the list of "valid Win32 identifiers", which removes the need for + * -mwin32) + */ +#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__)) + #define _WIN32 +#endif /* _WIN32 */ + +/* In order for extension support to be portable, we need to define an + * OpenGL function call method. We use the keyword APIENTRY, which is + * defined for Win32. (Note: Windows also needs this for ) + */ +#ifndef APIENTRY + #ifdef _WIN32 + #define APIENTRY __stdcall + #else + #define APIENTRY + #endif + #define GL_APIENTRY_DEFINED +#endif /* APIENTRY */ + + +/* The following three defines are here solely to make some Windows-based + * files happy. Theoretically we could include , but + * it has the major drawback of severely polluting our namespace. + */ + +/* Under Windows, we need WINGDIAPI defined */ +#if !defined(WINGDIAPI) && defined(_WIN32) + #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__) + /* Microsoft Visual C++, Borland C++ Builder and Pelles C */ + #define WINGDIAPI __declspec(dllimport) + #elif defined(__LCC__) + /* LCC-Win32 */ + #define WINGDIAPI __stdcall + #else + /* Others (e.g. MinGW, Cygwin) */ + #define WINGDIAPI extern + #endif + #define GL_WINGDIAPI_DEFINED +#endif /* WINGDIAPI */ + +/* Some files also need CALLBACK defined */ +#if !defined(CALLBACK) && defined(_WIN32) + #if defined(_MSC_VER) + /* Microsoft Visual C++ */ + #if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) + #define CALLBACK __stdcall + #else + #define CALLBACK + #endif + #else + /* Other Windows compilers */ + #define CALLBACK __stdcall + #endif + #define GLU_CALLBACK_DEFINED +#endif /* CALLBACK */ + +/* Microsoft Visual C++, Borland C++ and Pelles C needs wchar_t */ +#if defined(_WIN32) && (defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__)) && !defined(_WCHAR_T_DEFINED) + typedef unsigned short wchar_t; + #define _WCHAR_T_DEFINED +#endif /* _WCHAR_T_DEFINED */ + + +/* ---------------- GLFW related system specific defines ----------------- */ + +#if defined(_WIN32) && defined(GLFW_BUILD_DLL) + + /* We are building a Win32 DLL */ + #define GLFWAPI __declspec(dllexport) + +#elif defined(_WIN32) && defined(GLFW_DLL) + + /* We are calling a Win32 DLL */ + #if defined(__LCC__) + #define GLFWAPI extern + #else + #define GLFWAPI __declspec(dllimport) + #endif + +#else + + /* We are either building/calling a static lib or we are non-win32 */ + #define GLFWAPI + +#endif + +/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ + +/* Include standard OpenGL headers: GLFW uses GL_FALSE/GL_TRUE, and it is + * convenient for the user to only have to include . This also + * solves the problem with Windows and needing some + * special defines which normally requires the user to include + * (which is not a nice solution for portable programs). + */ +#if defined(__APPLE_CC__) + #include + #ifndef GLFW_NO_GLU + #include + #endif +#else + #include + #ifndef GLFW_NO_GLU + #include + #endif +#endif + + +/************************************************************************* + * GLFW version + *************************************************************************/ + +#define GLFW_VERSION_MAJOR 2 +#define GLFW_VERSION_MINOR 7 +#define GLFW_VERSION_REVISION 0 + + +/************************************************************************* + * Input handling definitions + *************************************************************************/ + +/* Key and button state/action definitions */ +#define GLFW_RELEASE 0 +#define GLFW_PRESS 1 + +/* Keyboard key definitions: 8-bit ISO-8859-1 (Latin 1) encoding is used + * for printable keys (such as A-Z, 0-9 etc), and values above 256 + * represent special (non-printable) keys (e.g. F1, Page Up etc). + */ +#define GLFW_KEY_UNKNOWN -1 +#define GLFW_KEY_SPACE 32 +#define GLFW_KEY_SPECIAL 256 +#define GLFW_KEY_ESC (GLFW_KEY_SPECIAL+1) +#define GLFW_KEY_F1 (GLFW_KEY_SPECIAL+2) +#define GLFW_KEY_F2 (GLFW_KEY_SPECIAL+3) +#define GLFW_KEY_F3 (GLFW_KEY_SPECIAL+4) +#define GLFW_KEY_F4 (GLFW_KEY_SPECIAL+5) +#define GLFW_KEY_F5 (GLFW_KEY_SPECIAL+6) +#define GLFW_KEY_F6 (GLFW_KEY_SPECIAL+7) +#define GLFW_KEY_F7 (GLFW_KEY_SPECIAL+8) +#define GLFW_KEY_F8 (GLFW_KEY_SPECIAL+9) +#define GLFW_KEY_F9 (GLFW_KEY_SPECIAL+10) +#define GLFW_KEY_F10 (GLFW_KEY_SPECIAL+11) +#define GLFW_KEY_F11 (GLFW_KEY_SPECIAL+12) +#define GLFW_KEY_F12 (GLFW_KEY_SPECIAL+13) +#define GLFW_KEY_F13 (GLFW_KEY_SPECIAL+14) +#define GLFW_KEY_F14 (GLFW_KEY_SPECIAL+15) +#define GLFW_KEY_F15 (GLFW_KEY_SPECIAL+16) +#define GLFW_KEY_F16 (GLFW_KEY_SPECIAL+17) +#define GLFW_KEY_F17 (GLFW_KEY_SPECIAL+18) +#define GLFW_KEY_F18 (GLFW_KEY_SPECIAL+19) +#define GLFW_KEY_F19 (GLFW_KEY_SPECIAL+20) +#define GLFW_KEY_F20 (GLFW_KEY_SPECIAL+21) +#define GLFW_KEY_F21 (GLFW_KEY_SPECIAL+22) +#define GLFW_KEY_F22 (GLFW_KEY_SPECIAL+23) +#define GLFW_KEY_F23 (GLFW_KEY_SPECIAL+24) +#define GLFW_KEY_F24 (GLFW_KEY_SPECIAL+25) +#define GLFW_KEY_F25 (GLFW_KEY_SPECIAL+26) +#define GLFW_KEY_UP (GLFW_KEY_SPECIAL+27) +#define GLFW_KEY_DOWN (GLFW_KEY_SPECIAL+28) +#define GLFW_KEY_LEFT (GLFW_KEY_SPECIAL+29) +#define GLFW_KEY_RIGHT (GLFW_KEY_SPECIAL+30) +#define GLFW_KEY_LSHIFT (GLFW_KEY_SPECIAL+31) +#define GLFW_KEY_RSHIFT (GLFW_KEY_SPECIAL+32) +#define GLFW_KEY_LCTRL (GLFW_KEY_SPECIAL+33) +#define GLFW_KEY_RCTRL (GLFW_KEY_SPECIAL+34) +#define GLFW_KEY_LALT (GLFW_KEY_SPECIAL+35) +#define GLFW_KEY_RALT (GLFW_KEY_SPECIAL+36) +#define GLFW_KEY_TAB (GLFW_KEY_SPECIAL+37) +#define GLFW_KEY_ENTER (GLFW_KEY_SPECIAL+38) +#define GLFW_KEY_BACKSPACE (GLFW_KEY_SPECIAL+39) +#define GLFW_KEY_INSERT (GLFW_KEY_SPECIAL+40) +#define GLFW_KEY_DEL (GLFW_KEY_SPECIAL+41) +#define GLFW_KEY_PAGEUP (GLFW_KEY_SPECIAL+42) +#define GLFW_KEY_PAGEDOWN (GLFW_KEY_SPECIAL+43) +#define GLFW_KEY_HOME (GLFW_KEY_SPECIAL+44) +#define GLFW_KEY_END (GLFW_KEY_SPECIAL+45) +#define GLFW_KEY_KP_0 (GLFW_KEY_SPECIAL+46) +#define GLFW_KEY_KP_1 (GLFW_KEY_SPECIAL+47) +#define GLFW_KEY_KP_2 (GLFW_KEY_SPECIAL+48) +#define GLFW_KEY_KP_3 (GLFW_KEY_SPECIAL+49) +#define GLFW_KEY_KP_4 (GLFW_KEY_SPECIAL+50) +#define GLFW_KEY_KP_5 (GLFW_KEY_SPECIAL+51) +#define GLFW_KEY_KP_6 (GLFW_KEY_SPECIAL+52) +#define GLFW_KEY_KP_7 (GLFW_KEY_SPECIAL+53) +#define GLFW_KEY_KP_8 (GLFW_KEY_SPECIAL+54) +#define GLFW_KEY_KP_9 (GLFW_KEY_SPECIAL+55) +#define GLFW_KEY_KP_DIVIDE (GLFW_KEY_SPECIAL+56) +#define GLFW_KEY_KP_MULTIPLY (GLFW_KEY_SPECIAL+57) +#define GLFW_KEY_KP_SUBTRACT (GLFW_KEY_SPECIAL+58) +#define GLFW_KEY_KP_ADD (GLFW_KEY_SPECIAL+59) +#define GLFW_KEY_KP_DECIMAL (GLFW_KEY_SPECIAL+60) +#define GLFW_KEY_KP_EQUAL (GLFW_KEY_SPECIAL+61) +#define GLFW_KEY_KP_ENTER (GLFW_KEY_SPECIAL+62) +#define GLFW_KEY_KP_NUM_LOCK (GLFW_KEY_SPECIAL+63) +#define GLFW_KEY_CAPS_LOCK (GLFW_KEY_SPECIAL+64) +#define GLFW_KEY_SCROLL_LOCK (GLFW_KEY_SPECIAL+65) +#define GLFW_KEY_PAUSE (GLFW_KEY_SPECIAL+66) +#define GLFW_KEY_LSUPER (GLFW_KEY_SPECIAL+67) +#define GLFW_KEY_RSUPER (GLFW_KEY_SPECIAL+68) +#define GLFW_KEY_MENU (GLFW_KEY_SPECIAL+69) +#define GLFW_KEY_LAST GLFW_KEY_MENU + +/* Mouse button definitions */ +#define GLFW_MOUSE_BUTTON_1 0 +#define GLFW_MOUSE_BUTTON_2 1 +#define GLFW_MOUSE_BUTTON_3 2 +#define GLFW_MOUSE_BUTTON_4 3 +#define GLFW_MOUSE_BUTTON_5 4 +#define GLFW_MOUSE_BUTTON_6 5 +#define GLFW_MOUSE_BUTTON_7 6 +#define GLFW_MOUSE_BUTTON_8 7 +#define GLFW_MOUSE_BUTTON_LAST GLFW_MOUSE_BUTTON_8 + +/* Mouse button aliases */ +#define GLFW_MOUSE_BUTTON_LEFT GLFW_MOUSE_BUTTON_1 +#define GLFW_MOUSE_BUTTON_RIGHT GLFW_MOUSE_BUTTON_2 +#define GLFW_MOUSE_BUTTON_MIDDLE GLFW_MOUSE_BUTTON_3 + +/* Joystick identifiers */ +#define GLFW_JOYSTICK_1 0 +#define GLFW_JOYSTICK_2 1 +#define GLFW_JOYSTICK_3 2 +#define GLFW_JOYSTICK_4 3 +#define GLFW_JOYSTICK_5 4 +#define GLFW_JOYSTICK_6 5 +#define GLFW_JOYSTICK_7 6 +#define GLFW_JOYSTICK_8 7 +#define GLFW_JOYSTICK_9 8 +#define GLFW_JOYSTICK_10 9 +#define GLFW_JOYSTICK_11 10 +#define GLFW_JOYSTICK_12 11 +#define GLFW_JOYSTICK_13 12 +#define GLFW_JOYSTICK_14 13 +#define GLFW_JOYSTICK_15 14 +#define GLFW_JOYSTICK_16 15 +#define GLFW_JOYSTICK_LAST GLFW_JOYSTICK_16 + + +/************************************************************************* + * Other definitions + *************************************************************************/ + +/* glfwOpenWindow modes */ +#define GLFW_WINDOW 0x00010001 +#define GLFW_FULLSCREEN 0x00010002 + +/* glfwGetWindowParam tokens */ +#define GLFW_OPENED 0x00020001 +#define GLFW_ACTIVE 0x00020002 +#define GLFW_ICONIFIED 0x00020003 +#define GLFW_ACCELERATED 0x00020004 +#define GLFW_RED_BITS 0x00020005 +#define GLFW_GREEN_BITS 0x00020006 +#define GLFW_BLUE_BITS 0x00020007 +#define GLFW_ALPHA_BITS 0x00020008 +#define GLFW_DEPTH_BITS 0x00020009 +#define GLFW_STENCIL_BITS 0x0002000A + +/* The following constants are used for both glfwGetWindowParam + * and glfwOpenWindowHint + */ +#define GLFW_REFRESH_RATE 0x0002000B +#define GLFW_ACCUM_RED_BITS 0x0002000C +#define GLFW_ACCUM_GREEN_BITS 0x0002000D +#define GLFW_ACCUM_BLUE_BITS 0x0002000E +#define GLFW_ACCUM_ALPHA_BITS 0x0002000F +#define GLFW_AUX_BUFFERS 0x00020010 +#define GLFW_STEREO 0x00020011 +#define GLFW_WINDOW_NO_RESIZE 0x00020012 +#define GLFW_FSAA_SAMPLES 0x00020013 +#define GLFW_OPENGL_VERSION_MAJOR 0x00020014 +#define GLFW_OPENGL_VERSION_MINOR 0x00020015 +#define GLFW_OPENGL_FORWARD_COMPAT 0x00020016 +#define GLFW_OPENGL_DEBUG_CONTEXT 0x00020017 +#define GLFW_OPENGL_PROFILE 0x00020018 + +/* GLFW_OPENGL_PROFILE tokens */ +#define GLFW_OPENGL_CORE_PROFILE 0x00050001 +#define GLFW_OPENGL_COMPAT_PROFILE 0x00050002 + +/* glfwEnable/glfwDisable tokens */ +#define GLFW_MOUSE_CURSOR 0x00030001 +#define GLFW_STICKY_KEYS 0x00030002 +#define GLFW_STICKY_MOUSE_BUTTONS 0x00030003 +#define GLFW_SYSTEM_KEYS 0x00030004 +#define GLFW_KEY_REPEAT 0x00030005 +#define GLFW_AUTO_POLL_EVENTS 0x00030006 + +/* glfwGetJoystickParam tokens */ +#define GLFW_PRESENT 0x00050001 +#define GLFW_AXES 0x00050002 +#define GLFW_BUTTONS 0x00050003 + + +/************************************************************************* + * Typedefs + *************************************************************************/ + +/* The video mode structure used by glfwGetVideoModes() */ +typedef struct { + int Width, Height; + int RedBits, BlueBits, GreenBits; +} GLFWvidmode; + +/* Function pointer types */ +typedef void (* GLFWwindowsizefun)(int,int); +typedef int (* GLFWwindowclosefun)(void); +typedef void (* GLFWwindowrefreshfun)(void); +typedef void (* GLFWmousebuttonfun)(int,int); +typedef void (* GLFWmouseposfun)(int,int); +typedef void (* GLFWmousewheelfun)(int); +typedef void (* GLFWkeyfun)(int,int); +typedef void (* GLFWcharfun)(int,int); + + +/************************************************************************* + * Prototypes + *************************************************************************/ + +/* GLFW initialization, termination and version querying */ +GLFWAPI int glfwInit( void ); +GLFWAPI void glfwTerminate( void ); +GLFWAPI void glfwGetVersion( int *major, int *minor, int *rev ); + +/* Window handling */ +GLFWAPI int glfwOpenWindow( int width, int height, int redbits, int greenbits, int bluebits, int alphabits, int depthbits, int stencilbits, int mode ); +GLFWAPI void glfwOpenWindowHint( int target, int hint ); +GLFWAPI void glfwCloseWindow( void ); +GLFWAPI void glfwSetWindowTitle( const char *title ); +GLFWAPI void glfwGetWindowSize( int *width, int *height ); +GLFWAPI void glfwSetWindowSize( int width, int height ); +GLFWAPI void glfwSetWindowPos( int x, int y ); +GLFWAPI void glfwIconifyWindow( void ); +GLFWAPI void glfwRestoreWindow( void ); +GLFWAPI void glfwSwapBuffers( void ); +GLFWAPI void glfwSwapInterval( int interval ); +GLFWAPI int glfwGetWindowParam( int param ); +GLFWAPI void glfwSetWindowSizeCallback( GLFWwindowsizefun cbfun ); +GLFWAPI void glfwSetWindowCloseCallback( GLFWwindowclosefun cbfun ); +GLFWAPI void glfwSetWindowRefreshCallback( GLFWwindowrefreshfun cbfun ); + +/* Video mode functions */ +GLFWAPI int glfwGetVideoModes( GLFWvidmode *list, int maxcount ); +GLFWAPI void glfwGetDesktopMode( GLFWvidmode *mode ); + +/* Input handling */ +GLFWAPI void glfwPollEvents( void ); +GLFWAPI void glfwWaitEvents( void ); +GLFWAPI int glfwGetKey( int key ); +GLFWAPI int glfwGetMouseButton( int button ); +GLFWAPI void glfwGetMousePos( int *xpos, int *ypos ); +GLFWAPI void glfwSetMousePos( int xpos, int ypos ); +GLFWAPI int glfwGetMouseWheel( void ); +GLFWAPI void glfwSetMouseWheel( int pos ); +GLFWAPI void glfwSetKeyCallback( GLFWkeyfun cbfun ); +GLFWAPI void glfwSetCharCallback( GLFWcharfun cbfun ); +GLFWAPI void glfwSetMouseButtonCallback( GLFWmousebuttonfun cbfun ); +GLFWAPI void glfwSetMousePosCallback( GLFWmouseposfun cbfun ); +GLFWAPI void glfwSetMouseWheelCallback( GLFWmousewheelfun cbfun ); + +/* Joystick input */ +GLFWAPI int glfwGetJoystickParam( int joy, int param ); +GLFWAPI int glfwGetJoystickPos( int joy, float *pos, int numaxes ); +GLFWAPI int glfwGetJoystickButtons( int joy, unsigned char *buttons, int numbuttons ); + +/* Time */ +GLFWAPI double glfwGetTime( void ); +GLFWAPI void glfwSetTime( double time ); + +/* Extension support */ +GLFWAPI int glfwExtensionSupported( const char *extension ); +GLFWAPI void* glfwGetProcAddress( const char *procname ); +GLFWAPI void glfwGetGLVersion( int *major, int *minor, int *rev ); + +/* Enable/disable functions */ +GLFWAPI void glfwEnable( int token ); +GLFWAPI void glfwDisable( int token ); + + +#ifdef __cplusplus +} +#endif + +#endif /* __glfw_h_ */ + diff --git a/lib/carbon/CMakeLists.txt b/lib/carbon/CMakeLists.txt new file mode 100644 index 00000000..51c98545 --- /dev/null +++ b/lib/carbon/CMakeLists.txt @@ -0,0 +1,38 @@ + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/libglfw.pc.cmake + ${CMAKE_CURRENT_BINARY_DIR}/libglfw.pc @ONLY) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/lib + ${GLFW_INCLUDE_DIR}) + +set(libglfw_SOURCES + ${common_SOURCES} + carbon_enable.c + carbon_fullscreen.c + carbon_glext.c + carbon_init.c + carbon_joystick.c + carbon_time.c + carbon_window.c) + +add_library(libglfwStatic STATIC ${libglfw_SOURCES}) +add_library(libglfwShared SHARED ${libglfw_SOURCES}) +target_link_libraries(libglfwShared ${GLFW_LIBRARIES}) +set_target_properties(libglfwStatic libglfwShared PROPERTIES + CLEAN_DIRECT_OUTPUT 1 + OUTPUT_NAME glfw +) + +# Append -fno-common to the compile flags to work around a bug in the Apple GCC +get_target_property(CFLAGS libglfwShared COMPILE_FLAGS) +if(NOT CFLAGS) + set(CFLAGS "") +endif(NOT CFLAGS) +set_target_properties(libglfwShared PROPERTIES COMPILE_FLAGS "${CFLAGS} -fno-common") + +install(TARGETS libglfwStatic libglfwShared DESTINATION lib) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libglfw.pc DESTINATION lib/pkgconfig) + diff --git a/lib/carbon/carbon_enable.c b/lib/carbon/carbon_enable.c new file mode 100644 index 00000000..76b18fef --- /dev/null +++ b/lib/carbon/carbon_enable.c @@ -0,0 +1,43 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Carbon/AGL/CGL +// API Version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2003 Keith Bauer +// Copyright (c) 2003-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +void _glfwPlatformEnableSystemKeys( void ) +{ + // Nothing to do; event handling code checks the status of + // _glfwWin.sysKeysDisabled to ensure this behavior. +} + +void _glfwPlatformDisableSystemKeys( void ) +{ + // Nothing to do; event handling code checks the status of + // _glfwWin.sysKeysDisabled to ensure this behavior. +} + diff --git a/lib/carbon/carbon_fullscreen.c b/lib/carbon/carbon_fullscreen.c new file mode 100644 index 00000000..2fd54570 --- /dev/null +++ b/lib/carbon/carbon_fullscreen.c @@ -0,0 +1,127 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Carbon/AGL/CGL +// API Version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2003 Keith Bauer +// Copyright (c) 2003-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +//======================================================================== +// _glfwVideoModesEqual() - Compares two video modes +//======================================================================== + +static int _glfwVideoModesEqual( GLFWvidmode* first, + GLFWvidmode* second ) +{ + if( first->Width != second->Width ) + return 0; + + if( first->Height != second->Height ) + return 0; + + if( first->RedBits + first->GreenBits + first->BlueBits != + second->RedBits + second->GreenBits + second->BlueBits ) + return 0; + + return 1; +} + +//======================================================================== +// _glfwCGToGLFWVideoMode() - Converts a CG mode to a GLFW mode +//======================================================================== + +static void _glfwCGToGLFWVideoMode( CFDictionaryRef cgMode, + GLFWvidmode* glfwMode ) +{ + int bitsPerSample; + + CFNumberGetValue( CFDictionaryGetValue( cgMode, kCGDisplayWidth ), + kCFNumberIntType, + &(glfwMode->Width) ); + CFNumberGetValue( CFDictionaryGetValue( cgMode, kCGDisplayHeight ), + kCFNumberIntType, + &(glfwMode->Height) ); + + CFNumberGetValue( CFDictionaryGetValue( cgMode, kCGDisplayBitsPerSample ), + kCFNumberIntType, + &bitsPerSample ); + + glfwMode->RedBits = bitsPerSample; + glfwMode->GreenBits = bitsPerSample; + glfwMode->BlueBits = bitsPerSample; +} + +//======================================================================== +// _glfwPlatformGetVideoModes() - Get a list of available video modes +//======================================================================== + +int _glfwPlatformGetVideoModes( GLFWvidmode *list, int maxcount ) +{ + int i, j, maxModes, numModes; + GLFWvidmode mode; + CFArrayRef availableModes = CGDisplayAvailableModes( kCGDirectMainDisplay ); + CFIndex numberOfAvailableModes = CFArrayGetCount( availableModes ); + + numModes = 0; + maxModes = ( numberOfAvailableModes < maxcount ? + numberOfAvailableModes : + maxcount ); + + for( i = 0; i < maxModes; ++i ) + { + _glfwCGToGLFWVideoMode( CFArrayGetValueAtIndex( availableModes, i ), + &mode ); + + // Is it a valid mode? (only list depths >= 15 bpp) + if( mode.RedBits + mode.GreenBits + mode.BlueBits < 15 ) + continue; + + // Check for duplicate of current mode in target list + for( j = 0; j < numModes; ++j ) + { + if( _glfwVideoModesEqual( &mode, &(list[j]) ) ) + break; + } + + // If empty list or no match found + if( numModes == 0 || j == numModes ) + list[numModes++] = mode; + } + + return numModes; +} + +//======================================================================== +// glfwGetDesktopMode() - Get the desktop video mode +//======================================================================== + +void _glfwPlatformGetDesktopMode( GLFWvidmode *mode ) +{ + _glfwCGToGLFWVideoMode( _glfwDesktopVideoMode, mode ); +} + diff --git a/lib/carbon/carbon_glext.c b/lib/carbon/carbon_glext.c new file mode 100644 index 00000000..2a1018fc --- /dev/null +++ b/lib/carbon/carbon_glext.c @@ -0,0 +1,53 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Carbon/AGL/CGL +// API Version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2003 Keith Bauer +// Copyright (c) 2003-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +int _glfwPlatformExtensionSupported( const char *extension ) +{ + // There are no AGL, CGL or NSGL extensions. + return GL_FALSE; +} + +void * _glfwPlatformGetProcAddress( const char *procname ) +{ + CFStringRef symbolName = CFStringCreateWithCString( kCFAllocatorDefault, + procname, + kCFStringEncodingASCII ); + + void *symbol = CFBundleGetFunctionPointerForName( _glfwLibrary.Libs.OpenGLFramework, + symbolName ); + + CFRelease( symbolName ); + + return symbol; +} + diff --git a/lib/carbon/carbon_init.c b/lib/carbon/carbon_init.c new file mode 100644 index 00000000..6a6d09ad --- /dev/null +++ b/lib/carbon/carbon_init.c @@ -0,0 +1,159 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Carbon/AGL/CGL +// API Version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2003 Keith Bauer +// Copyright (c) 2003-2010 Camilla Berglund +// Copyright (c) 2006-2007 Robin Leffmann +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include + +//======================================================================== +// Global variables +//======================================================================== + +// KCHR resource pointer for keycode translation +void *KCHRPtr; + + +//======================================================================== +// Terminate GLFW when exiting application +//======================================================================== + +static void glfw_atexit( void ) +{ + glfwTerminate(); +} + + +#define NO_BUNDLE_MESSAGE \ + "Working in unbundled mode. " \ + "You should build a .app wrapper for your Mac OS X applications.\n" + +#define UNBUNDLED \ + fprintf(stderr, NO_BUNDLE_MESSAGE); \ + _glfwLibrary.Unbundled = 1; \ + return + +void _glfwChangeToResourcesDirectory( void ) +{ + CFBundleRef mainBundle = CFBundleGetMainBundle(); + if( mainBundle == NULL ) + { + UNBUNDLED; + } + + CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL( mainBundle ); + char resourcesPath[ _GLFW_MAX_PATH_LENGTH ]; + + CFStringRef lastComponent = CFURLCopyLastPathComponent( resourcesURL ); + if( kCFCompareEqualTo != CFStringCompare( + CFSTR( "Resources" ), + lastComponent, + 0 ) ) + { + UNBUNDLED; + } + + CFRelease( lastComponent ); + + if( !CFURLGetFileSystemRepresentation( resourcesURL, + TRUE, + (UInt8*)resourcesPath, + _GLFW_MAX_PATH_LENGTH ) ) + { + CFRelease( resourcesURL ); + UNBUNDLED; + } + + CFRelease( resourcesURL ); + + if( chdir( resourcesPath ) != 0 ) + { + UNBUNDLED; + } +} + +int _glfwPlatformInit( void ) +{ + struct timeval tv; + UInt32 nullDummy = 0; + + _glfwWin.window = NULL; + _glfwWin.aglContext = NULL; + _glfwWin.cglContext = NULL; + _glfwWin.windowUPP = NULL; + + _glfwInput.Modifiers = 0; + + _glfwLibrary.Unbundled = 0; + + _glfwLibrary.Libs.OpenGLFramework = + CFBundleGetBundleWithIdentifier( CFSTR( "com.apple.opengl" ) ); + if( _glfwLibrary.Libs.OpenGLFramework == NULL ) + { + fprintf( stderr, "glfwInit failing because you aren't linked to OpenGL\n" ); + return GL_FALSE; + } + + _glfwDesktopVideoMode = CGDisplayCurrentMode( kCGDirectMainDisplay ); + if( _glfwDesktopVideoMode == NULL ) + { + fprintf( stderr, "glfwInit failing because it kind find the desktop display mode\n" ); + return GL_FALSE; + } + + // Install atexit routine + atexit( glfw_atexit ); + + _glfwChangeToResourcesDirectory(); + + // Ugly hack to reduce the nasty jump that occurs at the first non- + // sys keypress, caused by OS X loading certain meta scripts used + // for lexical- and raw keycode translation - instead of letting + // this happen while our application is running, we do some blunt + // function calls in advance just to get the script caching out of + // the way BEFORE our window/screen is opened. These calls might + // generate err return codes, but we don't care in this case. + // NOTE: KCHRPtr is declared globally, because we need it later on. + KCHRPtr = (void *)GetScriptVariable( smCurrentScript, smKCHRCache ); + KeyTranslate( KCHRPtr, 0, &nullDummy ); + UppercaseText( (char *)&nullDummy, 0, smSystemScript ); + + gettimeofday( &tv, NULL ); + _glfwLibrary.Timer.t0 = tv.tv_sec + (double) tv.tv_usec / 1000000.0; + + return GL_TRUE; +} + +int _glfwPlatformTerminate( void ) +{ + return GL_TRUE; +} + diff --git a/lib/carbon/carbon_joystick.c b/lib/carbon/carbon_joystick.c new file mode 100644 index 00000000..3cf47ac5 --- /dev/null +++ b/lib/carbon/carbon_joystick.c @@ -0,0 +1,51 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Carbon/AGL/CGL +// API Version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2003 Keith Bauer +// Copyright (c) 2003-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +// TO DO: use HID manager to implement joystick support. + +int _glfwPlatformGetJoystickParam( int joy, int param ) +{ + // GL_FALSE == 0 + return 0; +} + +int _glfwPlatformGetJoystickPos( int joy, float *pos, int numaxes ) +{ + return 0; +} + +int _glfwPlatformGetJoystickButtons( int joy, unsigned char *buttons, int numbuttons ) +{ + return 0; +} + diff --git a/lib/carbon/carbon_time.c b/lib/carbon/carbon_time.c new file mode 100644 index 00000000..64de6d70 --- /dev/null +++ b/lib/carbon/carbon_time.c @@ -0,0 +1,62 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Carbon/AGL/CGL +// API Version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2003 Keith Bauer +// Copyright (c) 2003-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Return timer value in seconds +//======================================================================== + +double _glfwPlatformGetTime( void ) +{ + struct timeval tv; + + gettimeofday( &tv, NULL ); + return tv.tv_sec + (double) tv.tv_usec / 1000000.0 - _glfwLibrary.Timer.t0; +} + + +//======================================================================== +// Set timer value in seconds +//======================================================================== + +void _glfwPlatformSetTime( double time ) +{ + struct timeval tv; + + gettimeofday( &tv, NULL ); + _glfwLibrary.Timer.t0 = tv.tv_sec + (double) tv.tv_usec / 1000000.0 - time; +} + diff --git a/lib/carbon/carbon_window.c b/lib/carbon/carbon_window.c new file mode 100644 index 00000000..4c709ede --- /dev/null +++ b/lib/carbon/carbon_window.c @@ -0,0 +1,1309 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Carbon/AGL/CGL +// API Version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2003 Keith Bauer +// Copyright (c) 2003-2010 Camilla Berglund +// Copyright (c) 2006-2007 Robin Leffmann +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#define _glfwTestModifier( modifierMask, glfwKey ) \ +if ( changed & modifierMask ) \ +{ \ + _glfwInputKey( glfwKey, (modifiers & modifierMask ? GLFW_PRESS : GLFW_RELEASE) ); \ +} + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +static void handleMacModifierChange( UInt32 modifiers ) +{ + UInt32 changed = modifiers ^ _glfwInput.Modifiers; + + // The right *key variants below never actually occur + // There also isn't even a broken right command key constant + _glfwTestModifier( shiftKey, GLFW_KEY_LSHIFT ); + _glfwTestModifier( rightShiftKey, GLFW_KEY_RSHIFT ); + _glfwTestModifier( controlKey, GLFW_KEY_LCTRL ); + _glfwTestModifier( rightControlKey, GLFW_KEY_RCTRL ); + _glfwTestModifier( optionKey, GLFW_KEY_LALT ); + _glfwTestModifier( rightOptionKey, GLFW_KEY_RALT ); + _glfwTestModifier( cmdKey, GLFW_KEY_LSUPER ); + + _glfwInput.Modifiers = modifiers; +} + +static void handleMacKeyChange( UInt32 keyCode, int action ) +{ + switch ( keyCode ) + { + case MAC_KEY_ENTER: _glfwInputKey( GLFW_KEY_ENTER, action); break; + case MAC_KEY_RETURN: _glfwInputKey( GLFW_KEY_KP_ENTER, action); break; + case MAC_KEY_ESC: _glfwInputKey( GLFW_KEY_ESC, action); break; + case MAC_KEY_F1: _glfwInputKey( GLFW_KEY_F1, action); break; + case MAC_KEY_F2: _glfwInputKey( GLFW_KEY_F2, action); break; + case MAC_KEY_F3: _glfwInputKey( GLFW_KEY_F3, action); break; + case MAC_KEY_F4: _glfwInputKey( GLFW_KEY_F4, action); break; + case MAC_KEY_F5: _glfwInputKey( GLFW_KEY_F5, action); break; + case MAC_KEY_F6: _glfwInputKey( GLFW_KEY_F6, action); break; + case MAC_KEY_F7: _glfwInputKey( GLFW_KEY_F7, action); break; + case MAC_KEY_F8: _glfwInputKey( GLFW_KEY_F8, action); break; + case MAC_KEY_F9: _glfwInputKey( GLFW_KEY_F9, action); break; + case MAC_KEY_F10: _glfwInputKey( GLFW_KEY_F10, action); break; + case MAC_KEY_F11: _glfwInputKey( GLFW_KEY_F11, action); break; + case MAC_KEY_F12: _glfwInputKey( GLFW_KEY_F12, action); break; + case MAC_KEY_F13: _glfwInputKey( GLFW_KEY_F13, action); break; + case MAC_KEY_F14: _glfwInputKey( GLFW_KEY_F14, action); break; + case MAC_KEY_F15: _glfwInputKey( GLFW_KEY_F15, action); break; + case MAC_KEY_UP: _glfwInputKey( GLFW_KEY_UP, action); break; + case MAC_KEY_DOWN: _glfwInputKey( GLFW_KEY_DOWN, action); break; + case MAC_KEY_LEFT: _glfwInputKey( GLFW_KEY_LEFT, action); break; + case MAC_KEY_RIGHT: _glfwInputKey( GLFW_KEY_RIGHT, action); break; + case MAC_KEY_TAB: _glfwInputKey( GLFW_KEY_TAB, action); break; + case MAC_KEY_BACKSPACE: _glfwInputKey( GLFW_KEY_BACKSPACE, action); break; + case MAC_KEY_HELP: _glfwInputKey( GLFW_KEY_INSERT, action); break; + case MAC_KEY_DEL: _glfwInputKey( GLFW_KEY_DEL, action); break; + case MAC_KEY_PAGEUP: _glfwInputKey( GLFW_KEY_PAGEUP, action); break; + case MAC_KEY_PAGEDOWN: _glfwInputKey( GLFW_KEY_PAGEDOWN, action); break; + case MAC_KEY_HOME: _glfwInputKey( GLFW_KEY_HOME, action); break; + case MAC_KEY_END: _glfwInputKey( GLFW_KEY_END, action); break; + case MAC_KEY_KP_0: _glfwInputKey( GLFW_KEY_KP_0, action); break; + case MAC_KEY_KP_1: _glfwInputKey( GLFW_KEY_KP_1, action); break; + case MAC_KEY_KP_2: _glfwInputKey( GLFW_KEY_KP_2, action); break; + case MAC_KEY_KP_3: _glfwInputKey( GLFW_KEY_KP_3, action); break; + case MAC_KEY_KP_4: _glfwInputKey( GLFW_KEY_KP_4, action); break; + case MAC_KEY_KP_5: _glfwInputKey( GLFW_KEY_KP_5, action); break; + case MAC_KEY_KP_6: _glfwInputKey( GLFW_KEY_KP_6, action); break; + case MAC_KEY_KP_7: _glfwInputKey( GLFW_KEY_KP_7, action); break; + case MAC_KEY_KP_8: _glfwInputKey( GLFW_KEY_KP_8, action); break; + case MAC_KEY_KP_9: _glfwInputKey( GLFW_KEY_KP_9, action); break; + case MAC_KEY_KP_DIVIDE: _glfwInputKey( GLFW_KEY_KP_DIVIDE, action); break; + case MAC_KEY_KP_MULTIPLY: _glfwInputKey( GLFW_KEY_KP_MULTIPLY, action); break; + case MAC_KEY_KP_SUBTRACT: _glfwInputKey( GLFW_KEY_KP_SUBTRACT, action); break; + case MAC_KEY_KP_ADD: _glfwInputKey( GLFW_KEY_KP_ADD, action); break; + case MAC_KEY_KP_DECIMAL: _glfwInputKey( GLFW_KEY_KP_DECIMAL, action); break; + case MAC_KEY_KP_EQUAL: _glfwInputKey( GLFW_KEY_KP_EQUAL, action); break; + case MAC_KEY_KP_ENTER: _glfwInputKey( GLFW_KEY_KP_ENTER, action); break; + case MAC_KEY_NUMLOCK: _glfwInputKey( GLFW_KEY_KP_NUM_LOCK, action); break; + default: + { + extern void *KCHRPtr; + UInt32 state = 0; + char charCode = (char)KeyTranslate( KCHRPtr, keyCode, &state ); + UppercaseText( &charCode, 1, smSystemScript ); + _glfwInputKey( (unsigned char)charCode, action ); + } + break; + } +} + +// The set of event class/kind combinations supported by keyEventHandler +// This is used by installEventHandlers below +static const EventTypeSpec GLFW_KEY_EVENT_TYPES[] = +{ + { kEventClassKeyboard, kEventRawKeyDown }, + { kEventClassKeyboard, kEventRawKeyUp }, + { kEventClassKeyboard, kEventRawKeyRepeat }, + { kEventClassKeyboard, kEventRawKeyModifiersChanged } +}; + +static OSStatus keyEventHandler( EventHandlerCallRef handlerCallRef, + EventRef event, + void *userData ) +{ + UInt32 keyCode; + short int keyChar; + UInt32 modifiers; + + switch( GetEventKind( event ) ) + { + case kEventRawKeyRepeat: + case kEventRawKeyDown: + { + if( GetEventParameter( event, + kEventParamKeyCode, + typeUInt32, + NULL, + sizeof( UInt32 ), + NULL, + &keyCode ) == noErr ) + { + handleMacKeyChange( keyCode, GLFW_PRESS ); + } + if( GetEventParameter( event, + kEventParamKeyUnicodes, + typeUnicodeText, + NULL, + sizeof(keyChar), + NULL, + &keyChar) == noErr ) + { + _glfwInputChar( keyChar, GLFW_PRESS ); + } + return noErr; + } + + case kEventRawKeyUp: + { + if( GetEventParameter( event, + kEventParamKeyCode, + typeUInt32, + NULL, + sizeof( UInt32 ), + NULL, + &keyCode ) == noErr ) + { + handleMacKeyChange( keyCode, GLFW_RELEASE ); + } + if( GetEventParameter( event, + kEventParamKeyUnicodes, + typeUnicodeText, + NULL, + sizeof(keyChar), + NULL, + &keyChar) == noErr ) + { + _glfwInputChar( keyChar, GLFW_RELEASE ); + } + return noErr; + } + + case kEventRawKeyModifiersChanged: + { + if( GetEventParameter( event, + kEventParamKeyModifiers, + typeUInt32, + NULL, + sizeof( UInt32 ), + NULL, + &modifiers ) == noErr ) + { + handleMacModifierChange( modifiers ); + return noErr; + } + } + break; + } + + return eventNotHandledErr; +} + +// The set of event class/kind combinations supported by mouseEventHandler +// This is used by installEventHandlers below +static const EventTypeSpec GLFW_MOUSE_EVENT_TYPES[] = +{ + { kEventClassMouse, kEventMouseDown }, + { kEventClassMouse, kEventMouseUp }, + { kEventClassMouse, kEventMouseMoved }, + { kEventClassMouse, kEventMouseDragged }, + { kEventClassMouse, kEventMouseWheelMoved }, +}; + +static OSStatus mouseEventHandler( EventHandlerCallRef handlerCallRef, + EventRef event, + void *userData ) +{ + switch( GetEventKind( event ) ) + { + case kEventMouseDown: + { + WindowRef window; + EventRecord oldStyleMacEvent; + ConvertEventRefToEventRecord( event, &oldStyleMacEvent ); + if( FindWindow ( oldStyleMacEvent.where, &window ) == inMenuBar ) + { + MenuSelect( oldStyleMacEvent.where ); + HiliteMenu(0); + return noErr; + } + else + { + EventMouseButton button; + if( GetEventParameter( event, + kEventParamMouseButton, + typeMouseButton, + NULL, + sizeof( EventMouseButton ), + NULL, + &button ) == noErr ) + { + button -= kEventMouseButtonPrimary; + if( button <= GLFW_MOUSE_BUTTON_LAST ) + { + _glfwInputMouseClick( button + GLFW_MOUSE_BUTTON_LEFT, + GLFW_PRESS ); + } + return noErr; + } + } + break; + } + + case kEventMouseUp: + { + EventMouseButton button; + if( GetEventParameter( event, + kEventParamMouseButton, + typeMouseButton, + NULL, + sizeof( EventMouseButton ), + NULL, + &button ) == noErr ) + { + button -= kEventMouseButtonPrimary; + if( button <= GLFW_MOUSE_BUTTON_LAST ) + { + _glfwInputMouseClick( button + GLFW_MOUSE_BUTTON_LEFT, + GLFW_RELEASE ); + } + return noErr; + } + break; + } + + case kEventMouseMoved: + case kEventMouseDragged: + { + HIPoint mouseLocation; + if( _glfwWin.mouseLock ) + { + if( GetEventParameter( event, + kEventParamMouseDelta, + typeHIPoint, + NULL, + sizeof( HIPoint ), + NULL, + &mouseLocation ) != noErr ) + { + break; + } + + _glfwInput.MousePosX += mouseLocation.x; + _glfwInput.MousePosY += mouseLocation.y; + } + else + { + if( GetEventParameter( event, + kEventParamMouseLocation, + typeHIPoint, + NULL, + sizeof( HIPoint ), + NULL, + &mouseLocation ) != noErr ) + { + break; + } + + _glfwInput.MousePosX = mouseLocation.x; + _glfwInput.MousePosY = mouseLocation.y; + + if( !_glfwWin.fullscreen ) + { + Rect content; + GetWindowBounds( _glfwWin.window, + kWindowContentRgn, + &content ); + + _glfwInput.MousePosX -= content.left; + _glfwInput.MousePosY -= content.top; + } + } + + if( _glfwWin.mousePosCallback ) + { + _glfwWin.mousePosCallback( _glfwInput.MousePosX, + _glfwInput.MousePosY ); + } + + break; + } + + case kEventMouseWheelMoved: + { + EventMouseWheelAxis axis; + if( GetEventParameter( event, + kEventParamMouseWheelAxis, + typeMouseWheelAxis, + NULL, + sizeof( EventMouseWheelAxis ), + NULL, + &axis) == noErr ) + { + long wheelDelta; + if( axis == kEventMouseWheelAxisY && + GetEventParameter( event, + kEventParamMouseWheelDelta, + typeLongInteger, + NULL, + sizeof( long ), + NULL, + &wheelDelta ) == noErr ) + { + _glfwInput.WheelPos += wheelDelta; + if( _glfwWin.mouseWheelCallback ) + { + _glfwWin.mouseWheelCallback( _glfwInput.WheelPos ); + } + return noErr; + } + } + break; + } + } + + return eventNotHandledErr; +} + +// The set of event class/kind combinations supported by commandHandler +// This is used by installEventHandlers below +static const EventTypeSpec GLFW_COMMAND_EVENT_TYPES[] = +{ + { kEventClassCommand, kEventCommandProcess } +}; + +static OSStatus commandHandler( EventHandlerCallRef handlerCallRef, + EventRef event, + void *userData ) +{ + if( _glfwWin.sysKeysDisabled ) + { + // TODO: Give adequate UI feedback that this is the case + return eventNotHandledErr; + } + + HICommand command; + if( GetEventParameter( event, + kEventParamDirectObject, + typeHICommand, + NULL, + sizeof( HICommand ), + NULL, + &command ) == noErr ) + { + switch( command.commandID ) + { + case kHICommandClose: + case kHICommandQuit: + { + // Check if the program wants us to close the window + if( _glfwWin.windowCloseCallback ) + { + if( _glfwWin.windowCloseCallback() ) + { + glfwCloseWindow(); + } + } + else + { + glfwCloseWindow(); + } + return noErr; + } + } + } + + return eventNotHandledErr; +} + +// The set of event class/kind combinations supported by windowEventHandler +// This is used by installEventHandlers below +static const EventTypeSpec GLFW_WINDOW_EVENT_TYPES[] = +{ + { kEventClassWindow, kEventWindowBoundsChanged }, + { kEventClassWindow, kEventWindowClose }, + { kEventClassWindow, kEventWindowDrawContent }, + { kEventClassWindow, kEventWindowActivated }, + { kEventClassWindow, kEventWindowDeactivated }, +}; + +static OSStatus windowEventHandler( EventHandlerCallRef handlerCallRef, + EventRef event, + void *userData ) +{ + switch( GetEventKind(event) ) + { + case kEventWindowBoundsChanged: + { + WindowRef window; + GetEventParameter( event, + kEventParamDirectObject, + typeWindowRef, + NULL, + sizeof(WindowRef), + NULL, + &window ); + + Rect rect; + GetWindowPortBounds( window, &rect ); + + if( _glfwWin.width != rect.right || + _glfwWin.height != rect.bottom ) + { + aglUpdateContext( _glfwWin.aglContext ); + + _glfwWin.width = rect.right; + _glfwWin.height = rect.bottom; + if( _glfwWin.windowSizeCallback ) + { + _glfwWin.windowSizeCallback( _glfwWin.width, _glfwWin.height ); + } + // Emulate (force) content invalidation + if( _glfwWin.windowRefreshCallback ) + { + _glfwWin.windowRefreshCallback(); + } + } + break; + } + + case kEventWindowClose: + { + // Check if the client wants us to close the window + if( _glfwWin.windowCloseCallback ) + { + if( _glfwWin.windowCloseCallback() ) + { + glfwCloseWindow(); + } + } + else + { + glfwCloseWindow(); + } + return noErr; + } + + case kEventWindowDrawContent: + { + if( _glfwWin.windowRefreshCallback ) + { + _glfwWin.windowRefreshCallback(); + } + break; + } + + case kEventWindowActivated: + { + _glfwWin.active = GL_TRUE; + break; + } + + case kEventWindowDeactivated: + { + _glfwWin.active = GL_FALSE; + _glfwInputDeactivation(); + break; + } + } + + return eventNotHandledErr; +} + +static int installEventHandlers( void ) +{ + OSStatus error; + + _glfwWin.mouseUPP = NewEventHandlerUPP( mouseEventHandler ); + + error = InstallEventHandler( GetApplicationEventTarget(), + _glfwWin.mouseUPP, + GetEventTypeCount( GLFW_MOUSE_EVENT_TYPES ), + GLFW_MOUSE_EVENT_TYPES, + NULL, + NULL ); + if( error != noErr ) + { + fprintf( stderr, "Failed to install Carbon application mouse event handler\n" ); + return GL_FALSE; + } + + _glfwWin.commandUPP = NewEventHandlerUPP( commandHandler ); + + error = InstallEventHandler( GetApplicationEventTarget(), + _glfwWin.commandUPP, + GetEventTypeCount( GLFW_COMMAND_EVENT_TYPES ), + GLFW_COMMAND_EVENT_TYPES, + NULL, + NULL ); + if( error != noErr ) + { + fprintf( stderr, "Failed to install Carbon application command event handler\n" ); + return GL_FALSE; + } + + _glfwWin.keyboardUPP = NewEventHandlerUPP( keyEventHandler ); + + error = InstallEventHandler( GetApplicationEventTarget(), + _glfwWin.keyboardUPP, + GetEventTypeCount( GLFW_KEY_EVENT_TYPES ), + GLFW_KEY_EVENT_TYPES, + NULL, + NULL ); + if( error != noErr ) + { + fprintf( stderr, "Failed to install Carbon application key event handler\n" ); + return GL_FALSE; + } + + return GL_TRUE; +} + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +#define _setAGLAttribute( aglAttributeName, AGLparameter ) \ +if ( AGLparameter != 0 ) \ +{ \ + AGLpixelFormatAttributes[numAGLAttrs++] = aglAttributeName; \ + AGLpixelFormatAttributes[numAGLAttrs++] = AGLparameter; \ +} + +#define _setCGLAttribute( cglAttributeName, CGLparameter ) \ +if ( CGLparameter != 0 ) \ +{ \ + CGLpixelFormatAttributes[ numCGLAttrs++ ] = cglAttributeName; \ + CGLpixelFormatAttributes[ numCGLAttrs++ ] = CGLparameter; \ +} + +//======================================================================== +// Here is where the window is created, and +// the OpenGL rendering context is created +//======================================================================== + +int _glfwPlatformOpenWindow( int width, int height, + const _GLFWwndconfig *wndconfig, + const _GLFWfbconfig *fbconfig ) +{ + OSStatus error; + unsigned int windowAttributes; + ProcessSerialNumber psn; + + // TODO: Break up this function! + + _glfwWin.windowUPP = NULL; + _glfwWin.mouseUPP = NULL; + _glfwWin.keyboardUPP = NULL; + _glfwWin.commandUPP = NULL; + _glfwWin.window = NULL; + _glfwWin.aglContext = NULL; + _glfwWin.aglPixelFormat = NULL; + _glfwWin.cglContext = NULL; + _glfwWin.cglPixelFormat = NULL; + + _glfwWin.refreshRate = wndconfig->refreshRate; + + // Fail if OpenGL 3.0 or above was requested + if( wndconfig->glMajor > 2 ) + { + fprintf( stderr, "OpenGL 3.0+ is not yet supported on Mac OS X\n" ); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + if( _glfwLibrary.Unbundled ) + { + if( GetCurrentProcess( &psn ) != noErr ) + { + fprintf( stderr, "Failed to get the process serial number\n" ); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + if( TransformProcessType( &psn, kProcessTransformToForegroundApplication ) != noErr ) + { + fprintf( stderr, "Failed to become a foreground application\n" ); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + if( wndconfig->mode == GLFW_FULLSCREEN ) + { + if( SetFrontProcess( &psn ) != noErr ) + { + fprintf( stderr, "Failed to become the front process\n" ); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + } + } + + if( !installEventHandlers() ) + { + fprintf( stderr, + "Failed to install Carbon application event handlers\n" ); + + _glfwPlatformTerminate(); + return GL_FALSE; + } + + // Windowed or fullscreen; AGL or CGL? Quite the mess... + // AGL appears to be the only choice for attaching OpenGL contexts to + // Carbon windows, but it leaves the user no control over fullscreen + // mode stretching. Solution: AGL for windowed, CGL for fullscreen. + if( wndconfig->mode == GLFW_WINDOW ) + { + // create AGL pixel format attribute list + GLint AGLpixelFormatAttributes[256]; + int numAGLAttrs = 0; + + AGLpixelFormatAttributes[numAGLAttrs++] = AGL_RGBA; + AGLpixelFormatAttributes[numAGLAttrs++] = AGL_DOUBLEBUFFER; + AGLpixelFormatAttributes[numAGLAttrs++] = AGL_CLOSEST_POLICY; + + if( fbconfig->stereo ) + { + AGLpixelFormatAttributes[numAGLAttrs++] = AGL_STEREO; + } + + _setAGLAttribute( AGL_AUX_BUFFERS, fbconfig->auxBuffers); + _setAGLAttribute( AGL_RED_SIZE, fbconfig->redBits ); + _setAGLAttribute( AGL_GREEN_SIZE, fbconfig->greenBits ); + _setAGLAttribute( AGL_BLUE_SIZE, fbconfig->blueBits ); + _setAGLAttribute( AGL_ALPHA_SIZE, fbconfig->alphaBits ); + _setAGLAttribute( AGL_DEPTH_SIZE, fbconfig->depthBits ); + _setAGLAttribute( AGL_STENCIL_SIZE, fbconfig->stencilBits ); + _setAGLAttribute( AGL_ACCUM_RED_SIZE, fbconfig->accumRedBits ); + _setAGLAttribute( AGL_ACCUM_GREEN_SIZE, fbconfig->accumGreenBits ); + _setAGLAttribute( AGL_ACCUM_BLUE_SIZE, fbconfig->accumBlueBits ); + _setAGLAttribute( AGL_ACCUM_ALPHA_SIZE, fbconfig->accumAlphaBits ); + + if( fbconfig->samples > 1 ) + { + _setAGLAttribute( AGL_SAMPLE_BUFFERS_ARB, 1 ); + _setAGLAttribute( AGL_SAMPLES_ARB, fbconfig->samples ); + AGLpixelFormatAttributes[numAGLAttrs++] = AGL_NO_RECOVERY; + } + + AGLpixelFormatAttributes[numAGLAttrs++] = AGL_NONE; + + // create pixel format descriptor + AGLDevice mainMonitor = GetMainDevice(); + _glfwWin.aglPixelFormat = aglChoosePixelFormat( &mainMonitor, + 1, + AGLpixelFormatAttributes ); + if( _glfwWin.aglPixelFormat == NULL ) + { + fprintf( stderr, + "Failed to choose AGL pixel format: %s\n", + aglErrorString( aglGetError() ) ); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // create AGL context + _glfwWin.aglContext = aglCreateContext( _glfwWin.aglPixelFormat, NULL ); + + if( _glfwWin.aglContext == NULL ) + { + fprintf( stderr, + "Failed to create AGL context: %s\n", + aglErrorString( aglGetError() ) ); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // create window + Rect windowContentBounds; + windowContentBounds.left = 0; + windowContentBounds.top = 0; + windowContentBounds.right = width; + windowContentBounds.bottom = height; + + windowAttributes = ( kWindowCloseBoxAttribute | + kWindowCollapseBoxAttribute | + kWindowStandardHandlerAttribute ); + + if( wndconfig->windowNoResize ) + { + windowAttributes |= kWindowLiveResizeAttribute; + } + else + { + windowAttributes |= ( kWindowFullZoomAttribute | + kWindowResizableAttribute ); + } + + error = CreateNewWindow( kDocumentWindowClass, + windowAttributes, + &windowContentBounds, + &( _glfwWin.window ) ); + if( ( error != noErr ) || ( _glfwWin.window == NULL ) ) + { + fprintf( stderr, "Failed to create Carbon window\n" ); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + _glfwWin.windowUPP = NewEventHandlerUPP( windowEventHandler ); + + error = InstallWindowEventHandler( _glfwWin.window, + _glfwWin.windowUPP, + GetEventTypeCount( GLFW_WINDOW_EVENT_TYPES ), + GLFW_WINDOW_EVENT_TYPES, + NULL, + NULL ); + if( error != noErr ) + { + fprintf( stderr, "Failed to install Carbon window event handler\n" ); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Don't care if we fail here + (void)SetWindowTitleWithCFString( _glfwWin.window, CFSTR( "GLFW Window" ) ); + (void)RepositionWindow( _glfwWin.window, + NULL, + kWindowCenterOnMainScreen ); + + if( !aglSetDrawable( _glfwWin.aglContext, + GetWindowPort( _glfwWin.window ) ) ) + { + fprintf( stderr, + "Failed to set the AGL context as the Carbon window drawable: %s\n", + aglErrorString( aglGetError() ) ); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Make OpenGL context current + if( !aglSetCurrentContext( _glfwWin.aglContext ) ) + { + fprintf( stderr, + "Failed to make AGL context current: %s\n", + aglErrorString( aglGetError() ) ); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + ShowWindow( _glfwWin.window ); + } + else + { + CGDisplayErr cgErr; + CGLError cglErr; + + CFDictionaryRef optimalMode; + + GLint numCGLvs = 0; + + CGLPixelFormatAttribute CGLpixelFormatAttributes[64]; + int numCGLAttrs = 0; + + // variables for enumerating color depths + GLint rgbColorDepth; + + // CGL pixel format attributes + _setCGLAttribute( kCGLPFADisplayMask, + CGDisplayIDToOpenGLDisplayMask( kCGDirectMainDisplay ) ); + + if( fbconfig->stereo ) + { + CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFAStereo; + } + + if( fbconfig->samples > 1 ) + { + _setCGLAttribute( kCGLPFASamples, (CGLPixelFormatAttribute)fbconfig->samples ); + _setCGLAttribute( kCGLPFASampleBuffers, (CGLPixelFormatAttribute)1 ); + CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFANoRecovery; + } + + CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFAFullScreen; + CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFADoubleBuffer; + CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFAAccelerated; + CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFANoRecovery; + CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFAMinimumPolicy; + + _setCGLAttribute( kCGLPFAAccumSize, + (CGLPixelFormatAttribute)( fbconfig->accumRedBits \ + + fbconfig->accumGreenBits \ + + fbconfig->accumBlueBits \ + + fbconfig->accumAlphaBits ) ); + + _setCGLAttribute( kCGLPFAAlphaSize, (CGLPixelFormatAttribute)fbconfig->alphaBits ); + _setCGLAttribute( kCGLPFADepthSize, (CGLPixelFormatAttribute)fbconfig->depthBits ); + _setCGLAttribute( kCGLPFAStencilSize, (CGLPixelFormatAttribute)fbconfig->stencilBits ); + _setCGLAttribute( kCGLPFAAuxBuffers, (CGLPixelFormatAttribute)fbconfig->auxBuffers ); + + CGLpixelFormatAttributes[ numCGLAttrs++ ] = (CGLPixelFormatAttribute)NULL; + + // create a suitable pixel format with above attributes.. + cglErr = CGLChoosePixelFormat( CGLpixelFormatAttributes, + &_glfwWin.cglPixelFormat, + &numCGLvs ); + if( cglErr != kCGLNoError ) + { + fprintf( stderr, + "Failed to choose CGL pixel format: %s\n", + CGLErrorString( cglErr ) ); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // ..and create a rendering context using that pixel format + cglErr = CGLCreateContext( _glfwWin.cglPixelFormat, NULL, &_glfwWin.cglContext ); + if( cglErr != kCGLNoError ) + { + fprintf( stderr, + "Failed to create CGL context: %s\n", + CGLErrorString( cglErr ) ); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // enumerate depth of RGB channels - unlike AGL, CGL works with + // a single parameter reflecting the full depth of the frame buffer + (void)CGLDescribePixelFormat( _glfwWin.cglPixelFormat, + 0, + kCGLPFAColorSize, + &rgbColorDepth ); + + // capture the display for our application + cgErr = CGCaptureAllDisplays(); + if( cgErr != kCGErrorSuccess ) + { + fprintf( stderr, + "Failed to capture Core Graphics displays\n"); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // find closest matching NON-STRETCHED display mode.. + optimalMode = CGDisplayBestModeForParametersAndRefreshRateWithProperty( + kCGDirectMainDisplay, + rgbColorDepth, + width, + height, + wndconfig->refreshRate, + NULL, + NULL ); + if( optimalMode == NULL ) + { + fprintf( stderr, + "Failed to retrieve Core Graphics display mode\n"); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // ..and switch to that mode + cgErr = CGDisplaySwitchToMode( kCGDirectMainDisplay, optimalMode ); + if( cgErr != kCGErrorSuccess ) + { + fprintf( stderr, + "Failed to switch to Core Graphics display mode\n"); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // switch to our OpenGL context, and bring it up fullscreen + cglErr = CGLSetCurrentContext( _glfwWin.cglContext ); + if( cglErr != kCGLNoError ) + { + fprintf( stderr, + "Failed to make CGL context current: %s\n", + CGLErrorString( cglErr ) ); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + cglErr = CGLSetFullScreen( _glfwWin.cglContext ); + if( cglErr != kCGLNoError ) + { + fprintf( stderr, + "Failed to set CGL fullscreen mode: %s\n", + CGLErrorString( cglErr ) ); + + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + } + + return GL_TRUE; +} + +//======================================================================== +// Properly kill the window/video display +//======================================================================== + +void _glfwPlatformCloseWindow( void ) +{ + if( _glfwWin.mouseUPP != NULL ) + { + DisposeEventHandlerUPP( _glfwWin.mouseUPP ); + _glfwWin.mouseUPP = NULL; + } + if( _glfwWin.commandUPP != NULL ) + { + DisposeEventHandlerUPP( _glfwWin.commandUPP ); + _glfwWin.commandUPP = NULL; + } + if( _glfwWin.keyboardUPP != NULL ) + { + DisposeEventHandlerUPP( _glfwWin.keyboardUPP ); + _glfwWin.keyboardUPP = NULL; + } + if( _glfwWin.windowUPP != NULL ) + { + DisposeEventHandlerUPP( _glfwWin.windowUPP ); + _glfwWin.windowUPP = NULL; + } + + if( _glfwWin.fullscreen ) + { + if( _glfwWin.cglContext != NULL ) + { + CGLSetCurrentContext( NULL ); + CGLClearDrawable( _glfwWin.cglContext ); + CGLDestroyContext( _glfwWin.cglContext ); + CGReleaseAllDisplays(); + _glfwWin.cglContext = NULL; + } + + if( _glfwWin.cglPixelFormat != NULL ) + { + CGLDestroyPixelFormat( _glfwWin.cglPixelFormat ); + _glfwWin.cglPixelFormat = NULL; + } + } + else + { + if( _glfwWin.aglContext != NULL ) + { + aglSetCurrentContext( NULL ); + aglSetDrawable( _glfwWin.aglContext, NULL ); + aglDestroyContext( _glfwWin.aglContext ); + _glfwWin.aglContext = NULL; + } + + if( _glfwWin.aglPixelFormat != NULL ) + { + aglDestroyPixelFormat( _glfwWin.aglPixelFormat ); + _glfwWin.aglPixelFormat = NULL; + } + } + + if( _glfwWin.window != NULL ) + { + ReleaseWindow( _glfwWin.window ); + _glfwWin.window = NULL; + } +} + +//======================================================================== +// Set the window title +//======================================================================== + +void _glfwPlatformSetWindowTitle( const char *title ) +{ + CFStringRef windowTitle; + + if( !_glfwWin.fullscreen ) + { + windowTitle = CFStringCreateWithCString( kCFAllocatorDefault, + title, + kCFStringEncodingISOLatin1 ); + + (void)SetWindowTitleWithCFString( _glfwWin.window, windowTitle ); + + CFRelease( windowTitle ); + } +} + +//======================================================================== +// Set the window size +//======================================================================== + +void _glfwPlatformSetWindowSize( int width, int height ) +{ + if( !_glfwWin.fullscreen ) + { + SizeWindow( _glfwWin.window, width, height, TRUE ); + } +} + +//======================================================================== +// Set the window position +//======================================================================== + +void _glfwPlatformSetWindowPos( int x, int y ) +{ + if( !_glfwWin.fullscreen ) + { + MoveWindow( _glfwWin.window, x, y, FALSE ); + } +} + +//======================================================================== +// Window iconification +//======================================================================== + +void _glfwPlatformIconifyWindow( void ) +{ + if( !_glfwWin.fullscreen ) + { + (void)CollapseWindow( _glfwWin.window, TRUE ); + } +} + +//======================================================================== +// Window un-iconification +//======================================================================== + +void _glfwPlatformRestoreWindow( void ) +{ + if( !_glfwWin.fullscreen ) + { + (void)CollapseWindow( _glfwWin.window, FALSE ); + } +} + +//======================================================================== +// Swap buffers (double-buffering) and poll any new events +//======================================================================== + +void _glfwPlatformSwapBuffers( void ) +{ + if( _glfwWin.fullscreen ) + { + CGLFlushDrawable( _glfwWin.cglContext ); + } + else + { + aglSwapBuffers( _glfwWin.aglContext ); + } +} + +//======================================================================== +// Set double buffering swap interval +//======================================================================== + +void _glfwPlatformSwapInterval( int interval ) +{ + GLint AGLparameter = interval; + + // CGL doesn't seem to like intervals other than 0 (vsync off) or 1 (vsync on) + long CGLparameter = ( interval ? 1 : 0 ); + + if( _glfwWin.fullscreen ) + { + // Don't care if we fail here.. + (void)CGLSetParameter( _glfwWin.cglContext, + kCGLCPSwapInterval, + (GLint*) &CGLparameter ); + } + else + { + // ..or here + (void)aglSetInteger( _glfwWin.aglContext, + AGL_SWAP_INTERVAL, + &AGLparameter ); + } +} + +//======================================================================== +// Read back framebuffer parameters from the context +//======================================================================== + +#define _getAGLAttribute( aglAttributeName, variableName ) \ +{ \ + GLint aglValue; \ + (void)aglDescribePixelFormat( _glfwWin.aglPixelFormat, aglAttributeName, &aglValue ); \ + variableName = aglValue; \ +} + +#define _getCGLAttribute( cglAttributeName, variableName ) \ +{ \ + GLint cglValue; \ + (void)CGLDescribePixelFormat( _glfwWin.cglPixelFormat, 0, cglAttributeName, &cglValue ); \ + variableName = cglValue; \ +} + +void _glfwPlatformRefreshWindowParams( void ) +{ + GLint rgbColorDepth; + GLint rgbaAccumDepth = 0; + GLint rgbChannelDepth = 0; + + if( _glfwWin.fullscreen ) + { + _getCGLAttribute( kCGLPFAAccelerated, _glfwWin.accelerated ); + _getCGLAttribute( kCGLPFAAlphaSize, _glfwWin.alphaBits ); + _getCGLAttribute( kCGLPFADepthSize, _glfwWin.depthBits ); + _getCGLAttribute( kCGLPFAStencilSize, _glfwWin.stencilBits ); + _getCGLAttribute( kCGLPFAAuxBuffers, _glfwWin.auxBuffers ); + _getCGLAttribute( kCGLPFAStereo, _glfwWin.stereo ); + _getCGLAttribute( kCGLPFASamples, _glfwWin.samples ); + + // Enumerate depth of RGB channels - unlike AGL, CGL works with + // a single parameter reflecting the full depth of the frame buffer + (void)CGLDescribePixelFormat( _glfwWin.cglPixelFormat, + 0, + kCGLPFAColorSize, + &rgbColorDepth ); + + if( rgbColorDepth == 24 || rgbColorDepth == 32 ) + { + rgbChannelDepth = 8; + } + if( rgbColorDepth == 16 ) + { + rgbChannelDepth = 5; + } + + _glfwWin.redBits = rgbChannelDepth; + _glfwWin.greenBits = rgbChannelDepth; + _glfwWin.blueBits = rgbChannelDepth; + + // Get pixel depth of accumulator - I haven't got the slightest idea + // how this number conforms to any other channel depth than 8 bits, + // so this might end up giving completely knackered results... + _getCGLAttribute( kCGLPFAColorSize, rgbaAccumDepth ); + if( rgbaAccumDepth == 32 ) + { + rgbaAccumDepth = 8; + } + + _glfwWin.accumRedBits = rgbaAccumDepth; + _glfwWin.accumGreenBits = rgbaAccumDepth; + _glfwWin.accumBlueBits = rgbaAccumDepth; + _glfwWin.accumAlphaBits = rgbaAccumDepth; + } + else + { + _getAGLAttribute( AGL_ACCELERATED, _glfwWin.accelerated ); + _getAGLAttribute( AGL_RED_SIZE, _glfwWin.redBits ); + _getAGLAttribute( AGL_GREEN_SIZE, _glfwWin.greenBits ); + _getAGLAttribute( AGL_BLUE_SIZE, _glfwWin.blueBits ); + _getAGLAttribute( AGL_ALPHA_SIZE, _glfwWin.alphaBits ); + _getAGLAttribute( AGL_DEPTH_SIZE, _glfwWin.depthBits ); + _getAGLAttribute( AGL_STENCIL_SIZE, _glfwWin.stencilBits ); + _getAGLAttribute( AGL_ACCUM_RED_SIZE, _glfwWin.accumRedBits ); + _getAGLAttribute( AGL_ACCUM_GREEN_SIZE, _glfwWin.accumGreenBits ); + _getAGLAttribute( AGL_ACCUM_BLUE_SIZE, _glfwWin.accumBlueBits ); + _getAGLAttribute( AGL_ACCUM_ALPHA_SIZE, _glfwWin.accumAlphaBits ); + _getAGLAttribute( AGL_AUX_BUFFERS, _glfwWin.auxBuffers ); + _getAGLAttribute( AGL_STEREO, _glfwWin.stereo ); + _getAGLAttribute( AGL_SAMPLES_ARB, _glfwWin.samples ); + } +} + +//======================================================================== +// Poll for new window and input events +//======================================================================== + +void _glfwPlatformPollEvents( void ) +{ + EventRef event; + EventTargetRef eventDispatcher = GetEventDispatcherTarget(); + + while ( ReceiveNextEvent( 0, NULL, 0.0, TRUE, &event ) == noErr ) + { + SendEventToEventTarget( event, eventDispatcher ); + ReleaseEvent( event ); + } +} + +//======================================================================== +// Wait for new window and input events +//======================================================================== + +void _glfwPlatformWaitEvents( void ) +{ + EventRef event; + + // Wait for new events + ReceiveNextEvent( 0, NULL, kEventDurationForever, FALSE, &event ); + + // Process the new events + _glfwPlatformPollEvents(); +} + +//======================================================================== +// Hide mouse cursor (lock it) +//======================================================================== + +void _glfwPlatformHideMouseCursor( void ) +{ + CGDisplayHideCursor( kCGDirectMainDisplay ); + CGAssociateMouseAndMouseCursorPosition( false ); +} + +//======================================================================== +// Show mouse cursor (unlock it) +//======================================================================== + +void _glfwPlatformShowMouseCursor( void ) +{ + CGDisplayShowCursor( kCGDirectMainDisplay ); + CGAssociateMouseAndMouseCursorPosition( true ); +} + +//======================================================================== +// Set physical mouse cursor position +//======================================================================== + +void _glfwPlatformSetMouseCursorPos( int x, int y ) +{ + Rect content; + + if( _glfwWin.fullscreen ) + { + CGDisplayMoveCursorToPoint( kCGDirectMainDisplay, + CGPointMake( x, y ) ); + } + else + { + GetWindowBounds(_glfwWin.window, kWindowContentRgn, &content); + + _glfwInput.MousePosX = x + content.left; + _glfwInput.MousePosY = y + content.top; + + CGDisplayMoveCursorToPoint( kCGDirectMainDisplay, + CGPointMake( _glfwInput.MousePosX, + _glfwInput.MousePosY ) ); + } +} + diff --git a/lib/carbon/libglfw.pc.cmake b/lib/carbon/libglfw.pc.cmake new file mode 100644 index 00000000..2700c59d --- /dev/null +++ b/lib/carbon/libglfw.pc.cmake @@ -0,0 +1,11 @@ +prefix=@PREFIX@ +exec_prefix=@PREFIX@ +libdir=@PREFIX@/lib +includedir=@PREFIX@/include + +Name: GLFW +Description: A portable framework for OpenGL development +Version: 2.7 +URL: http://glfw.sourceforge.net/ +Libs: -L${libdir} -lglfw -framework AGL -framework OpenGL -framework Carbon +Cflags: -I${includedir} diff --git a/lib/carbon/platform.h b/lib/carbon/platform.h new file mode 100644 index 00000000..f39751c7 --- /dev/null +++ b/lib/carbon/platform.h @@ -0,0 +1,268 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Carbon/AGL/CGL +// API Version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2003 Keith Bauer +// Copyright (c) 2003-2010 Camilla Berglund +// Copyright (c) 2006-2007 Robin Leffmann +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _platform_h_ +#define _platform_h_ + + +// This is the Mac OS X version of GLFW +#define _GLFW_MAC_OS_X + +#include +#include +#include + +#include "../../include/GL/glfw.h" + +#if MACOSX_DEPLOYMENT_TARGET < MAC_OS_X_VERSION_10_3 + +#ifndef kCGLNoError +#define kCGLNoError 0 +#endif + +#endif + + +#ifndef GL_VERSION_3_0 + +typedef const GLubyte * (APIENTRY *PFNGLGETSTRINGIPROC) (GLenum, GLuint); + +#endif /*GL_VERSION_3_0*/ + + +//======================================================================== +// Defines +//======================================================================== + +#define _GLFW_MAX_PATH_LENGTH (8192) + +#define MAC_KEY_ENTER 0x24 +#define MAC_KEY_RETURN 0x34 +#define MAC_KEY_ESC 0x35 +#define MAC_KEY_F1 0x7A +#define MAC_KEY_F2 0x78 +#define MAC_KEY_F3 0x63 +#define MAC_KEY_F4 0x76 +#define MAC_KEY_F5 0x60 +#define MAC_KEY_F6 0x61 +#define MAC_KEY_F7 0x62 +#define MAC_KEY_F8 0x64 +#define MAC_KEY_F9 0x65 +#define MAC_KEY_F10 0x6D +#define MAC_KEY_F11 0x67 +#define MAC_KEY_F12 0x6F +#define MAC_KEY_F13 0x69 +#define MAC_KEY_F14 0x6B +#define MAC_KEY_F15 0x71 +#define MAC_KEY_UP 0x7E +#define MAC_KEY_DOWN 0x7D +#define MAC_KEY_LEFT 0x7B +#define MAC_KEY_RIGHT 0x7C +#define MAC_KEY_TAB 0x30 +#define MAC_KEY_BACKSPACE 0x33 +#define MAC_KEY_HELP 0x72 +#define MAC_KEY_DEL 0x75 +#define MAC_KEY_PAGEUP 0x74 +#define MAC_KEY_PAGEDOWN 0x79 +#define MAC_KEY_HOME 0x73 +#define MAC_KEY_END 0x77 +#define MAC_KEY_KP_0 0x52 +#define MAC_KEY_KP_1 0x53 +#define MAC_KEY_KP_2 0x54 +#define MAC_KEY_KP_3 0x55 +#define MAC_KEY_KP_4 0x56 +#define MAC_KEY_KP_5 0x57 +#define MAC_KEY_KP_6 0x58 +#define MAC_KEY_KP_7 0x59 +#define MAC_KEY_KP_8 0x5B +#define MAC_KEY_KP_9 0x5C +#define MAC_KEY_KP_DIVIDE 0x4B +#define MAC_KEY_KP_MULTIPLY 0x43 +#define MAC_KEY_KP_SUBTRACT 0x4E +#define MAC_KEY_KP_ADD 0x45 +#define MAC_KEY_KP_DECIMAL 0x41 +#define MAC_KEY_KP_EQUAL 0x51 +#define MAC_KEY_KP_ENTER 0x4C +#define MAC_KEY_NUMLOCK 0x47 + + +//======================================================================== +// GLFW platform specific types +//======================================================================== + +//------------------------------------------------------------------------ +// Pointer length integer +//------------------------------------------------------------------------ +typedef intptr_t GLFWintptr; + + +GLFWGLOBAL CFDictionaryRef _glfwDesktopVideoMode; + +//------------------------------------------------------------------------ +// Window structure +//------------------------------------------------------------------------ +typedef struct _GLFWwin_struct _GLFWwin; + +struct _GLFWwin_struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // User callback functions + GLFWwindowsizefun windowSizeCallback; + GLFWwindowclosefun windowCloseCallback; + GLFWwindowrefreshfun windowRefreshCallback; + GLFWmousebuttonfun mouseButtonCallback; + GLFWmouseposfun mousePosCallback; + GLFWmousewheelfun mouseWheelCallback; + GLFWkeyfun keyCallback; + GLFWcharfun charCallback; + + // User selected window settings + int fullscreen; // Fullscreen flag + int mouseLock; // Mouse-lock flag + int autoPollEvents; // Auto polling flag + int sysKeysDisabled; // System keys disabled flag + int windowNoResize; // Resize- and maximize gadgets disabled flag + int refreshRate; // Vertical monitor refresh rate + + // Window status & parameters + int opened; // Flag telling if window is opened or not + int active; // Application active flag + int iconified; // Window iconified flag + int width, height; // Window width and heigth + int accelerated; // GL_TRUE if window is HW accelerated + + // Framebuffer attributes + int redBits; + int greenBits; + int blueBits; + int alphaBits; + int depthBits; + int stencilBits; + int accumRedBits; + int accumGreenBits; + int accumBlueBits; + int accumAlphaBits; + int auxBuffers; + int stereo; + int samples; + + // OpenGL extensions and context attributes + int has_GL_SGIS_generate_mipmap; + int has_GL_ARB_texture_non_power_of_two; + int glMajor, glMinor, glRevision; + int glForward, glDebug, glProfile; + + PFNGLGETSTRINGIPROC GetStringi; + +// ========= PLATFORM SPECIFIC PART ====================================== + + WindowRef window; + + AGLContext aglContext; + AGLPixelFormat aglPixelFormat; + + CGLContextObj cglContext; + CGLPixelFormatObj cglPixelFormat; + + EventHandlerUPP windowUPP; + EventHandlerUPP mouseUPP; + EventHandlerUPP commandUPP; + EventHandlerUPP keyboardUPP; +}; + +GLFWGLOBAL _GLFWwin _glfwWin; + + +//------------------------------------------------------------------------ +// User input status (some of this should go in _GLFWwin) +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Mouse status + int MousePosX, MousePosY; + int WheelPos; + char MouseButton[ GLFW_MOUSE_BUTTON_LAST + 1 ]; + + // Keyboard status + char Key[ GLFW_KEY_LAST + 1 ]; + int LastChar; + + // User selected settings + int StickyKeys; + int StickyMouseButtons; + int KeyRepeat; + +// ========= PLATFORM SPECIFIC PART ====================================== + + UInt32 Modifiers; + +} _glfwInput; + + + +//------------------------------------------------------------------------ +// Library global data +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Window opening hints + _GLFWhints hints; + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Timer data + struct { + double t0; + } Timer; + + struct { + // Bundle for dynamically-loading extension function pointers + CFBundleRef OpenGLFramework; + } Libs; + + int Unbundled; + +} _glfwLibrary; + + +//======================================================================== +// Prototypes for platform specific internal functions +//======================================================================== + +void _glfwChangeToResourcesDirectory( void ); + +#endif // _platform_h_ diff --git a/lib/cocoa/CMakeLists.txt b/lib/cocoa/CMakeLists.txt new file mode 100644 index 00000000..115e9bf2 --- /dev/null +++ b/lib/cocoa/CMakeLists.txt @@ -0,0 +1,44 @@ + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/libglfw.pc.cmake + ${CMAKE_CURRENT_BINARY_DIR}/libglfw.pc @ONLY) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/lib + ${GLFW_INCLUDE_DIR}) + +set(cocoa_SOURCES + cocoa_enable.m + cocoa_fullscreen.m + cocoa_glext.m + cocoa_init.m + cocoa_joystick.m + cocoa_time.m + cocoa_window.m) + +# For some reason, CMake doesn't know about .m +set_source_files_properties(${cocoa_SOURCES} PROPERTIES LANGUAGE C) + +set(libglfw_SOURCES + ${common_SOURCES} + ${cocoa_SOURCES}) + +add_library(libglfwStatic STATIC ${libglfw_SOURCES}) +add_library(libglfwShared SHARED ${libglfw_SOURCES}) +target_link_libraries(libglfwShared ${GLFW_LIBRARIES}) +set_target_properties(libglfwStatic libglfwShared PROPERTIES + CLEAN_DIRECT_OUTPUT 1 + OUTPUT_NAME glfw +) + +# Append -fno-common to the compile flags to work around a bug in the Apple GCC +get_target_property(CFLAGS libglfwShared COMPILE_FLAGS) +if(NOT CFLAGS) + set(CFLAGS "") +endif(NOT CFLAGS) +set_target_properties(libglfwShared PROPERTIES COMPILE_FLAGS "${CFLAGS} -fno-common") + +install(TARGETS libglfwStatic libglfwShared DESTINATION lib) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libglfw.pc DESTINATION lib/pkgconfig) + diff --git a/lib/cocoa/cocoa_enable.m b/lib/cocoa/cocoa_enable.m new file mode 100644 index 00000000..7e194766 --- /dev/null +++ b/lib/cocoa/cocoa_enable.m @@ -0,0 +1,51 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Cocoa/NSOpenGL +// API Version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2009-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Enable and disable system keys +//======================================================================== + +void _glfwPlatformEnableSystemKeys( void ) +{ + // This is checked in macosx_window.m; we take no action here +} + +void _glfwPlatformDisableSystemKeys( void ) +{ + // This is checked in macosx_window.m; we take no action here + // I don't think it's really possible to disable stuff like Exposé + // except in full-screen mode. +} + diff --git a/lib/cocoa/cocoa_fullscreen.m b/lib/cocoa/cocoa_fullscreen.m new file mode 100644 index 00000000..e716cee7 --- /dev/null +++ b/lib/cocoa/cocoa_fullscreen.m @@ -0,0 +1,102 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Cocoa/NSOpenGL +// API Version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2009-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +//======================================================================== +// Check whether the display mode should be included in enumeration +//======================================================================== + +static BOOL modeIsGood( NSDictionary *mode ) +{ + // This is a bit controversial, if you've got something other than an + // LCD computer monitor as an output device you might not want these + // checks. You might also want to reject modes which are interlaced, + // or TV out. There is no one-size-fits-all policy that can work here. + // This seems like a decent compromise, but certain applications may + // wish to patch this... + return [[mode objectForKey:(id)kCGDisplayBitsPerPixel] intValue] >= 15 && + [mode objectForKey:(id)kCGDisplayModeIsSafeForHardware] != nil && + [mode objectForKey:(id)kCGDisplayModeIsStretched] == nil; +} + +//======================================================================== +// Convert Core Graphics display mode to GLFW video mode +//======================================================================== + +static GLFWvidmode vidmodeFromCGDisplayMode( NSDictionary *mode ) +{ + unsigned int width = [[mode objectForKey:(id)kCGDisplayWidth] unsignedIntValue]; + unsigned int height = [[mode objectForKey:(id)kCGDisplayHeight] unsignedIntValue]; + unsigned int bps = [[mode objectForKey:(id)kCGDisplayBitsPerSample] unsignedIntValue]; + + GLFWvidmode result; + result.Width = width; + result.Height = height; + result.RedBits = bps; + result.GreenBits = bps; + result.BlueBits = bps; + return result; +} + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Get a list of available video modes +//======================================================================== + +int _glfwPlatformGetVideoModes( GLFWvidmode *list, int maxcount ) +{ + NSArray *modes = (NSArray *)CGDisplayAvailableModes( CGMainDisplayID() ); + + unsigned int i, j = 0, n = [modes count]; + for( i = 0; i < n && i < (unsigned)maxcount; i++ ) + { + NSDictionary *mode = [modes objectAtIndex:i]; + if( modeIsGood( mode ) ) + { + list[j++] = vidmodeFromCGDisplayMode( mode ); + } + } + + return j; +} + +//======================================================================== +// Get the desktop video mode +//======================================================================== + +void _glfwPlatformGetDesktopMode( GLFWvidmode *mode ) +{ + *mode = vidmodeFromCGDisplayMode( _glfwLibrary.DesktopMode ); +} + diff --git a/lib/cocoa/cocoa_glext.m b/lib/cocoa/cocoa_glext.m new file mode 100644 index 00000000..860b0041 --- /dev/null +++ b/lib/cocoa/cocoa_glext.m @@ -0,0 +1,63 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Cocoa/NSOpenGL +// API Version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2009-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Check if an OpenGL extension is available at runtime +//======================================================================== + +int _glfwPlatformExtensionSupported( const char *extension ) +{ + // There are no AGL, CGL or NSGL extensions. + return GL_FALSE; +} + +//======================================================================== +// Get the function pointer to an OpenGL function +//======================================================================== + +void * _glfwPlatformGetProcAddress( const char *procname ) +{ + CFStringRef symbolName = CFStringCreateWithCString( kCFAllocatorDefault, + procname, + kCFStringEncodingASCII ); + + void *symbol = CFBundleGetFunctionPointerForName( _glfwLibrary.OpenGLFramework, + symbolName ); + + CFRelease( symbolName ); + + return symbol; +} + diff --git a/lib/cocoa/cocoa_init.m b/lib/cocoa/cocoa_init.m new file mode 100644 index 00000000..94cf1293 --- /dev/null +++ b/lib/cocoa/cocoa_init.m @@ -0,0 +1,250 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Cocoa/NSOpenGL +// API Version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2009-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +// Needed for _NSGetProgname +#include + +#include "internal.h" + +@interface GLFWApplication : NSApplication +@end + +@implementation GLFWApplication + +// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost +// This works around an AppKit bug, where key up events while holding +// down the command key don't get sent to the key window. +- (void)sendEvent:(NSEvent *)event +{ + if( [event type] == NSKeyUp && ( [event modifierFlags] & NSCommandKeyMask ) ) + { + [[self keyWindow] sendEvent:event]; + } + else + { + [super sendEvent:event]; + } +} + +@end + +// Prior to Snow Leopard, we need to use this oddly-named semi-private API +// to get the application menu working properly. Need to be careful in +// case it goes away in a future OS update. +@interface NSApplication (NSAppleMenu) +- (void)setAppleMenu:(NSMenu *)m; +@end + +// Keys to search for as potential application names +NSString *GLFWNameKeys[] = +{ + @"CFBundleDisplayName", + @"CFBundleName", + @"CFBundleExecutable", +}; + +//======================================================================== +// Try to figure out what the calling application is called +//======================================================================== +static NSString *findAppName( void ) +{ + NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary]; + + unsigned int i; + for( i = 0; i < sizeof(GLFWNameKeys) / sizeof(GLFWNameKeys[0]); i++ ) + { + id name = [infoDictionary objectForKey:GLFWNameKeys[i]]; + if (name && + [name isKindOfClass:[NSString class]] && + ![@"" isEqualToString:name]) + { + return name; + } + } + + // If we get here, we're unbundled + if( !_glfwLibrary.Unbundled ) + { + // Could do this only if we discover we're unbundled, but it should + // do no harm... + ProcessSerialNumber psn = { 0, kCurrentProcess }; + TransformProcessType( &psn, kProcessTransformToForegroundApplication ); + + // Having the app in front of the terminal window is also generally + // handy. There is an NSApplication API to do this, but... + SetFrontProcess( &psn ); + + _glfwLibrary.Unbundled = GL_TRUE; + } + + char **progname = _NSGetProgname(); + if( progname && *progname ) + { + // TODO: UTF8? + return [NSString stringWithUTF8String:*progname]; + } + + // Really shouldn't get here + return @"GLFW Application"; +} + +//======================================================================== +// Set up the menu bar (manually) +// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that +// could go away at any moment, lots of stuff that really should be +// localize(d|able), etc. Loading a nib would save us this horror, but that +// doesn't seem like a good thing to require of GLFW's clients. +//======================================================================== +static void setUpMenuBar( void ) +{ + NSString *appName = findAppName(); + + NSMenu *bar = [[NSMenu alloc] init]; + [NSApp setMainMenu:bar]; + + NSMenuItem *appMenuItem = + [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; + NSMenu *appMenu = [[NSMenu alloc] init]; + [appMenuItem setSubmenu:appMenu]; + + [appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName] + action:@selector(orderFrontStandardAboutPanel:) + keyEquivalent:@""]; + [appMenu addItem:[NSMenuItem separatorItem]]; + NSMenu *servicesMenu = [[NSMenu alloc] init]; + [NSApp setServicesMenu:servicesMenu]; + [[appMenu addItemWithTitle:@"Services" + action:NULL + keyEquivalent:@""] setSubmenu:servicesMenu]; + [appMenu addItem:[NSMenuItem separatorItem]]; + [appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName] + action:@selector(hide:) + keyEquivalent:@"h"]; + [[appMenu addItemWithTitle:@"Hide Others" + action:@selector(hideOtherApplications:) + keyEquivalent:@"h"] + setKeyEquivalentModifierMask:NSAlternateKeyMask | NSCommandKeyMask]; + [appMenu addItemWithTitle:@"Show All" + action:@selector(unhideAllApplications:) + keyEquivalent:@""]; + [appMenu addItem:[NSMenuItem separatorItem]]; + [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName] + action:@selector(terminate:) + keyEquivalent:@"q"]; + + NSMenuItem *windowMenuItem = + [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; + NSMenu *windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; + [NSApp setWindowsMenu:windowMenu]; + [windowMenuItem setSubmenu:windowMenu]; + + [windowMenu addItemWithTitle:@"Miniaturize" + action:@selector(performMiniaturize:) + keyEquivalent:@"m"]; + [windowMenu addItemWithTitle:@"Zoom" + action:@selector(performZoom:) + keyEquivalent:@""]; + [windowMenu addItem:[NSMenuItem separatorItem]]; + [windowMenu addItemWithTitle:@"Bring All to Front" + action:@selector(arrangeInFront:) + keyEquivalent:@""]; + + // At least guard the call to private API to avoid an exception if it + // goes away. Hopefully that means the worst we'll break in future is to + // look ugly... + if( [NSApp respondsToSelector:@selector(setAppleMenu:)] ) + { + [NSApp setAppleMenu:appMenu]; + } +} + +//======================================================================== +// Terminate GLFW when exiting application +//======================================================================== + +static void glfw_atexit( void ) +{ + glfwTerminate(); +} + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Initialize the GLFW library +//======================================================================== + +int _glfwPlatformInit( void ) +{ + _glfwLibrary.AutoreleasePool = [[NSAutoreleasePool alloc] init]; + + // Implicitly create shared NSApplication instance + [GLFWApplication sharedApplication]; + + NSString* resourcePath = [[NSBundle mainBundle] resourcePath]; + + if( access( [resourcePath cStringUsingEncoding:NSUTF8StringEncoding], R_OK ) == 0 ) + { + chdir( [resourcePath cStringUsingEncoding:NSUTF8StringEncoding] ); + } + + // Setting up menu bar must go exactly here else weirdness ensues + setUpMenuBar(); + + [NSApp finishLaunching]; + + // Install atexit routine + atexit( glfw_atexit ); + + _glfwPlatformSetTime( 0.0 ); + + _glfwLibrary.DesktopMode = + (NSDictionary *)CGDisplayCurrentMode( CGMainDisplayID() ); + + return GL_TRUE; +} + +//======================================================================== +// Close window, if open, and shut down GLFW +//======================================================================== + +int _glfwPlatformTerminate( void ) +{ + glfwCloseWindow(); + + // TODO: Probably other cleanup + + [_glfwLibrary.AutoreleasePool release]; + _glfwLibrary.AutoreleasePool = nil; + + return GL_TRUE; +} + diff --git a/lib/cocoa/cocoa_joystick.m b/lib/cocoa/cocoa_joystick.m new file mode 100644 index 00000000..bd3ea640 --- /dev/null +++ b/lib/cocoa/cocoa_joystick.m @@ -0,0 +1,65 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Cocoa/NSOpenGL +// API Version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2009-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Determine joystick capabilities +//======================================================================== + +int _glfwPlatformGetJoystickParam( int joy, int param ) +{ + // TODO: Implement this. + return 0; +} + +//======================================================================== +// Get joystick axis positions +//======================================================================== + +int _glfwPlatformGetJoystickPos( int joy, float *pos, int numaxes ) +{ + // TODO: Implement this. + return 0; +} + +//======================================================================== +// Get joystick button states +//======================================================================== + +int _glfwPlatformGetJoystickButtons( int joy, unsigned char *buttons, int numbuttons ) +{ + // TODO: Implement this. + return 0; +} + diff --git a/lib/cocoa/cocoa_time.m b/lib/cocoa/cocoa_time.m new file mode 100644 index 00000000..df68b24b --- /dev/null +++ b/lib/cocoa/cocoa_time.m @@ -0,0 +1,53 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Cocoa/NSOpenGL +// API Version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2009-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Return timer value in seconds +//======================================================================== + +double _glfwPlatformGetTime( void ) +{ + return [NSDate timeIntervalSinceReferenceDate] - _glfwLibrary.Timer.t0; +} + +//======================================================================== +// Set timer value in seconds +//======================================================================== + +void _glfwPlatformSetTime( double time ) +{ + _glfwLibrary.Timer.t0 = [NSDate timeIntervalSinceReferenceDate] - time; +} + diff --git a/lib/cocoa/cocoa_window.m b/lib/cocoa/cocoa_window.m new file mode 100644 index 00000000..7bc0b996 --- /dev/null +++ b/lib/cocoa/cocoa_window.m @@ -0,0 +1,886 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Cocoa/NSOpenGL +// API Version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2009-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +//======================================================================== +// Delegate for window related notifications +// (but also used as an application delegate) +//======================================================================== + +@interface GLFWWindowDelegate : NSObject +@end + +@implementation GLFWWindowDelegate + +- (BOOL)windowShouldClose:(id)window +{ + if( _glfwWin.windowCloseCallback ) + { + if( !_glfwWin.windowCloseCallback() ) + { + return NO; + } + } + + // This is horribly ugly, but it works + glfwCloseWindow(); + return NO; +} + +- (void)windowDidResize:(NSNotification *)notification +{ + [_glfwWin.context update]; + + NSRect contentRect = + [_glfwWin.window contentRectForFrameRect:[_glfwWin.window frame]]; + _glfwWin.width = contentRect.size.width; + _glfwWin.height = contentRect.size.height; + + if( _glfwWin.windowSizeCallback ) + { + _glfwWin.windowSizeCallback( _glfwWin.width, _glfwWin.height ); + } +} + +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender +{ + if( _glfwWin.windowCloseCallback ) + { + if( !_glfwWin.windowCloseCallback() ) + { + return NSTerminateCancel; + } + } + + // This is horribly ugly, but it works + glfwCloseWindow(); + return NSTerminateCancel; +} + +@end + +// TODO: Need to find mappings for F13-F15, volume down/up/mute, and eject. +static const unsigned int MAC_TO_GLFW_KEYCODE_MAPPING[128] = +{ + /* 00 */ 'A', + /* 01 */ 'S', + /* 02 */ 'D', + /* 03 */ 'F', + /* 04 */ 'H', + /* 05 */ 'G', + /* 06 */ 'Z', + /* 07 */ 'X', + /* 08 */ 'C', + /* 09 */ 'V', + /* 0a */ -1, + /* 0b */ 'B', + /* 0c */ 'Q', + /* 0d */ 'W', + /* 0e */ 'E', + /* 0f */ 'R', + /* 10 */ 'Y', + /* 11 */ 'T', + /* 12 */ '1', + /* 13 */ '2', + /* 14 */ '3', + /* 15 */ '4', + /* 16 */ '6', + /* 17 */ '5', + /* 18 */ '=', + /* 19 */ '9', + /* 1a */ '7', + /* 1b */ '-', + /* 1c */ '8', + /* 1d */ '0', + /* 1e */ ']', + /* 1f */ 'O', + /* 20 */ 'U', + /* 21 */ '[', + /* 22 */ 'I', + /* 23 */ 'P', + /* 24 */ GLFW_KEY_ENTER, + /* 25 */ 'L', + /* 26 */ 'J', + /* 27 */ '\'', + /* 28 */ 'K', + /* 29 */ ';', + /* 2a */ '\\', + /* 2b */ ',', + /* 2c */ '/', + /* 2d */ 'N', + /* 2e */ 'M', + /* 2f */ '.', + /* 30 */ GLFW_KEY_TAB, + /* 31 */ GLFW_KEY_SPACE, + /* 32 */ '`', + /* 33 */ GLFW_KEY_BACKSPACE, + /* 34 */ -1, + /* 35 */ GLFW_KEY_ESC, + /* 36 */ GLFW_KEY_RSUPER, + /* 37 */ GLFW_KEY_LSUPER, + /* 38 */ GLFW_KEY_LSHIFT, + /* 39 */ GLFW_KEY_CAPS_LOCK, + /* 3a */ GLFW_KEY_LALT, + /* 3b */ GLFW_KEY_LCTRL, + /* 3c */ GLFW_KEY_RSHIFT, + /* 3d */ GLFW_KEY_RALT, + /* 3e */ GLFW_KEY_RCTRL, + /* 3f */ -1, /*Function*/ + /* 40 */ GLFW_KEY_F17, + /* 41 */ GLFW_KEY_KP_DECIMAL, + /* 42 */ -1, + /* 43 */ GLFW_KEY_KP_MULTIPLY, + /* 44 */ -1, + /* 45 */ GLFW_KEY_KP_ADD, + /* 46 */ -1, + /* 47 */ -1, /*KeypadClear*/ + /* 48 */ -1, /*VolumeUp*/ + /* 49 */ -1, /*VolumeDown*/ + /* 4a */ -1, /*Mute*/ + /* 4b */ GLFW_KEY_KP_DIVIDE, + /* 4c */ GLFW_KEY_KP_ENTER, + /* 4d */ -1, + /* 4e */ GLFW_KEY_KP_SUBTRACT, + /* 4f */ GLFW_KEY_F18, + /* 50 */ GLFW_KEY_F19, + /* 51 */ GLFW_KEY_KP_EQUAL, + /* 52 */ GLFW_KEY_KP_0, + /* 53 */ GLFW_KEY_KP_1, + /* 54 */ GLFW_KEY_KP_2, + /* 55 */ GLFW_KEY_KP_3, + /* 56 */ GLFW_KEY_KP_4, + /* 57 */ GLFW_KEY_KP_5, + /* 58 */ GLFW_KEY_KP_6, + /* 59 */ GLFW_KEY_KP_7, + /* 5a */ GLFW_KEY_F20, + /* 5b */ GLFW_KEY_KP_8, + /* 5c */ GLFW_KEY_KP_9, + /* 5d */ -1, + /* 5e */ -1, + /* 5f */ -1, + /* 60 */ GLFW_KEY_F5, + /* 61 */ GLFW_KEY_F6, + /* 62 */ GLFW_KEY_F7, + /* 63 */ GLFW_KEY_F3, + /* 64 */ GLFW_KEY_F8, + /* 65 */ GLFW_KEY_F9, + /* 66 */ -1, + /* 67 */ GLFW_KEY_F11, + /* 68 */ -1, + /* 69 */ GLFW_KEY_F13, + /* 6a */ GLFW_KEY_F16, + /* 6b */ GLFW_KEY_F14, + /* 6c */ -1, + /* 6d */ GLFW_KEY_F10, + /* 6e */ -1, + /* 6f */ GLFW_KEY_F12, + /* 70 */ -1, + /* 71 */ GLFW_KEY_F15, + /* 72 */ GLFW_KEY_INSERT, /*Help*/ + /* 73 */ GLFW_KEY_HOME, + /* 74 */ GLFW_KEY_PAGEUP, + /* 75 */ GLFW_KEY_DEL, + /* 76 */ GLFW_KEY_F4, + /* 77 */ GLFW_KEY_END, + /* 78 */ GLFW_KEY_F2, + /* 79 */ GLFW_KEY_PAGEDOWN, + /* 7a */ GLFW_KEY_F1, + /* 7b */ GLFW_KEY_LEFT, + /* 7c */ GLFW_KEY_RIGHT, + /* 7d */ GLFW_KEY_DOWN, + /* 7e */ GLFW_KEY_UP, + /* 7f */ -1, +}; + +//======================================================================== +// Converts a Mac OS X keycode to a GLFW keycode +//======================================================================== + +static int convertMacKeyCode( unsigned int macKeyCode ) +{ + if( macKeyCode >= 128 ) + { + return -1; + } + + // This treats keycodes as *positional*; that is, we'll return 'a' + // for the key left of 's', even on an AZERTY keyboard. The charInput + // function should still get 'q' though. + return MAC_TO_GLFW_KEYCODE_MAPPING[macKeyCode]; +} + +//======================================================================== +// Content view class for the GLFW window +//======================================================================== + +@interface GLFWContentView : NSView +@end + +@implementation GLFWContentView + +- (BOOL)isOpaque +{ + return YES; +} + +- (BOOL)canBecomeKeyView +{ + return YES; +} + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +- (void)mouseDown:(NSEvent *)event +{ + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS ); +} + +- (void)mouseDragged:(NSEvent *)event +{ + [self mouseMoved:event]; +} + +- (void)mouseUp:(NSEvent *)event +{ + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE ); +} + +- (void)mouseMoved:(NSEvent *)event +{ + if( _glfwWin.mouseLock ) + { + _glfwInput.MousePosX += [event deltaX]; + _glfwInput.MousePosY += [event deltaY]; + } + else + { + NSPoint p = [event locationInWindow]; + + // Cocoa coordinate system has origin at lower left + _glfwInput.MousePosX = p.x; + _glfwInput.MousePosY = [[_glfwWin.window contentView] bounds].size.height - p.y; + } + + if( _glfwWin.mousePosCallback ) + { + _glfwWin.mousePosCallback( _glfwInput.MousePosX, _glfwInput.MousePosY ); + } +} + +- (void)rightMouseDown:(NSEvent *)event +{ + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS ); +} + +- (void)rightMouseDragged:(NSEvent *)event +{ + [self mouseMoved:event]; +} + +- (void)rightMouseUp:(NSEvent *)event +{ + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE ); +} + +- (void)otherMouseDown:(NSEvent *)event +{ + _glfwInputMouseClick( [event buttonNumber], GLFW_PRESS ); +} + +- (void)otherMouseDragged:(NSEvent *)event +{ + [self mouseMoved:event]; +} + +- (void)otherMouseUp:(NSEvent *)event +{ + _glfwInputMouseClick( [event buttonNumber], GLFW_RELEASE ); +} + +- (void)keyDown:(NSEvent *)event +{ + NSUInteger length; + NSString* characters; + int i, code = convertMacKeyCode( [event keyCode] ); + + if( code != -1 ) + { + _glfwInputKey( code, GLFW_PRESS ); + + if( [event modifierFlags] & NSCommandKeyMask ) + { + if( !_glfwWin.sysKeysDisabled ) + { + [super keyDown:event]; + } + } + else + { + characters = [event characters]; + length = [characters length]; + + for( i = 0; i < length; i++ ) + { + _glfwInputChar( [characters characterAtIndex:i], GLFW_PRESS ); + } + } + } +} + +- (void)flagsChanged:(NSEvent *)event +{ + unsigned int newModifierFlags = [event modifierFlags] | NSDeviceIndependentModifierFlagsMask; + int mode; + + if( newModifierFlags > _glfwWin.modifierFlags ) + { + mode = GLFW_PRESS; + } + else + { + mode = GLFW_RELEASE; + } + + _glfwWin.modifierFlags = newModifierFlags; + _glfwInputKey( MAC_TO_GLFW_KEYCODE_MAPPING[[event keyCode]], mode ); +} + +- (void)keyUp:(NSEvent *)event +{ + NSUInteger length; + NSString* characters; + int i, code = convertMacKeyCode( [event keyCode] ); + + if( code != -1 ) + { + _glfwInputKey( code, GLFW_RELEASE ); + + characters = [event characters]; + length = [characters length]; + + for( i = 0; i < length; i++ ) + { + _glfwInputChar( [characters characterAtIndex:i], GLFW_RELEASE ); + } + } +} + +- (void)scrollWheel:(NSEvent *)event +{ + _glfwInput.WheelPosFloating += [event deltaY]; + _glfwInput.WheelPos = lrint(_glfwInput.WheelPosFloating); + + if( _glfwWin.mouseWheelCallback ) + { + _glfwWin.mouseWheelCallback( _glfwInput.WheelPos ); + } +} + +@end + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Here is where the window is created, and the OpenGL rendering context is +// created +//======================================================================== + +int _glfwPlatformOpenWindow( int width, int height, + const _GLFWwndconfig *wndconfig, + const _GLFWfbconfig *fbconfig ) +{ + int colorBits; + + _glfwWin.pixelFormat = nil; + _glfwWin.window = nil; + _glfwWin.context = nil; + _glfwWin.delegate = nil; + + // Fail if OpenGL 3.0 or above was requested + if( wndconfig->glMajor > 2 ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + _glfwWin.delegate = [[GLFWWindowDelegate alloc] init]; + if( _glfwWin.delegate == nil ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + [NSApp setDelegate:_glfwWin.delegate]; + + // Mac OS X needs non-zero color size, so set resonable values + colorBits = fbconfig->redBits + fbconfig->greenBits + fbconfig->blueBits; + if( colorBits == 0 ) + { + colorBits = 24; + } + else if( colorBits < 15 ) + { + colorBits = 15; + } + + // Ignored hints: + // OpenGLMajor, OpenGLMinor, OpenGLForward: + // pending Mac OS X support for OpenGL 3.x + // OpenGLDebug + // pending it meaning anything on Mac OS X + + // Don't use accumulation buffer support; it's not accelerated + // Aux buffers probably aren't accelerated either + + CFDictionaryRef fullscreenMode = NULL; + if( wndconfig->mode == GLFW_FULLSCREEN ) + { + fullscreenMode = + // I think it's safe to pass 0 to the refresh rate for this function + // rather than conditionalizing the code to call the version which + // doesn't specify refresh... + CGDisplayBestModeForParametersAndRefreshRateWithProperty( + CGMainDisplayID(), + colorBits + fbconfig->alphaBits, + width, + height, + wndconfig->refreshRate, + // Controversial, see macosx_fullscreen.m for discussion + kCGDisplayModeIsSafeForHardware, + NULL); + + width = [[(id)fullscreenMode objectForKey:(id)kCGDisplayWidth] intValue]; + height = [[(id)fullscreenMode objectForKey:(id)kCGDisplayHeight] intValue]; + } + + unsigned int styleMask = 0; + if( wndconfig->mode == GLFW_WINDOW ) + { + styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask; + + if( !wndconfig->windowNoResize ) + { + styleMask |= NSResizableWindowMask; + } + } + else + { + styleMask = NSBorderlessWindowMask; + } + + _glfwWin.window = [[NSWindow alloc] + initWithContentRect:NSMakeRect(0, 0, width, height) + styleMask:styleMask + backing:NSBackingStoreBuffered + defer:NO]; + [_glfwWin.window setContentView:[[GLFWContentView alloc] init]]; + [_glfwWin.window setDelegate:_glfwWin.delegate]; + [_glfwWin.window setAcceptsMouseMovedEvents:YES]; + [_glfwWin.window center]; + + if( wndconfig->mode == GLFW_FULLSCREEN ) + { + CGCaptureAllDisplays(); + CGDisplaySwitchToMode( CGMainDisplayID(), fullscreenMode ); + } + + unsigned int attribute_count = 0; +#define ADD_ATTR(x) attributes[attribute_count++] = x +#define ADD_ATTR2(x, y) (void)({ ADD_ATTR(x); ADD_ATTR(y); }) +#define MAX_ATTRS 24 // urgh + NSOpenGLPixelFormatAttribute attributes[MAX_ATTRS]; + + ADD_ATTR( NSOpenGLPFADoubleBuffer ); + + if( wndconfig->mode == GLFW_FULLSCREEN ) + { + ADD_ATTR( NSOpenGLPFAFullScreen ); + ADD_ATTR( NSOpenGLPFANoRecovery ); + ADD_ATTR2( NSOpenGLPFAScreenMask, + CGDisplayIDToOpenGLDisplayMask( CGMainDisplayID() ) ); + } + + ADD_ATTR2( NSOpenGLPFAColorSize, colorBits ); + + if( fbconfig->alphaBits > 0) + { + ADD_ATTR2( NSOpenGLPFAAlphaSize, fbconfig->alphaBits ); + } + + if( fbconfig->depthBits > 0) + { + ADD_ATTR2( NSOpenGLPFADepthSize, fbconfig->depthBits ); + } + + if( fbconfig->stencilBits > 0) + { + ADD_ATTR2( NSOpenGLPFAStencilSize, fbconfig->stencilBits ); + } + + int accumBits = fbconfig->accumRedBits + fbconfig->accumGreenBits + + fbconfig->accumBlueBits + fbconfig->accumAlphaBits; + + if( accumBits > 0) + { + ADD_ATTR2( NSOpenGLPFAAccumSize, accumBits ); + } + + if( fbconfig->auxBuffers > 0) + { + ADD_ATTR2( NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers ); + } + + if( fbconfig->stereo) + { + ADD_ATTR( NSOpenGLPFAStereo ); + } + + if( fbconfig->samples > 0) + { + ADD_ATTR2( NSOpenGLPFASampleBuffers, 1 ); + ADD_ATTR2( NSOpenGLPFASamples, fbconfig->samples ); + } + + ADD_ATTR(0); + + _glfwWin.pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; + if( _glfwWin.pixelFormat == nil ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + _glfwWin.context = [[NSOpenGLContext alloc] initWithFormat:_glfwWin.pixelFormat + shareContext:nil]; + if( _glfwWin.context == nil ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + [_glfwWin.window makeKeyAndOrderFront:nil]; + [_glfwWin.context setView:[_glfwWin.window contentView]]; + + if( wndconfig->mode == GLFW_FULLSCREEN ) + { + // TODO: Make this work on pre-Leopard systems + [[_glfwWin.window contentView] enterFullScreenMode:[NSScreen mainScreen] + withOptions:nil]; + } + + [_glfwWin.context makeCurrentContext]; + + NSPoint point = [[NSCursor currentCursor] hotSpot]; + _glfwInput.MousePosX = point.x; + _glfwInput.MousePosY = point.y; + + return GL_TRUE; +} + +//======================================================================== +// Properly kill the window / video display +//======================================================================== + +void _glfwPlatformCloseWindow( void ) +{ + [_glfwWin.window orderOut:nil]; + + if( _glfwWin.fullscreen ) + { + [[_glfwWin.window contentView] exitFullScreenModeWithOptions:nil]; + CGDisplaySwitchToMode( CGMainDisplayID(), + (CFDictionaryRef)_glfwLibrary.DesktopMode ); + CGReleaseAllDisplays(); + } + + [_glfwWin.pixelFormat release]; + _glfwWin.pixelFormat = nil; + + [NSOpenGLContext clearCurrentContext]; + [_glfwWin.context release]; + _glfwWin.context = nil; + + [_glfwWin.window setDelegate:nil]; + [NSApp setDelegate:nil]; + [_glfwWin.delegate release]; + _glfwWin.delegate = nil; + + [_glfwWin.window close]; + _glfwWin.window = nil; + + // TODO: Probably more cleanup +} + +//======================================================================== +// Set the window title +//======================================================================== + +void _glfwPlatformSetWindowTitle( const char *title ) +{ + [_glfwWin.window setTitle:[NSString stringWithCString:title + encoding:NSISOLatin1StringEncoding]]; +} + +//======================================================================== +// Set the window size +//======================================================================== + +void _glfwPlatformSetWindowSize( int width, int height ) +{ + [_glfwWin.window setContentSize:NSMakeSize(width, height)]; +} + +//======================================================================== +// Set the window position +//======================================================================== + +void _glfwPlatformSetWindowPos( int x, int y ) +{ + NSRect contentRect = [_glfwWin.window contentRectForFrameRect:[_glfwWin.window frame]]; + + // We assume here that the client code wants to position the window within the + // screen the window currently occupies + NSRect screenRect = [[_glfwWin.window screen] visibleFrame]; + contentRect.origin = NSMakePoint(screenRect.origin.x + x, + screenRect.origin.y + screenRect.size.height - + y - contentRect.size.height); + + [_glfwWin.window setFrame:[_glfwWin.window frameRectForContentRect:contentRect] + display:YES]; +} + +//======================================================================== +// Iconify the window +//======================================================================== + +void _glfwPlatformIconifyWindow( void ) +{ + [_glfwWin.window miniaturize:nil]; +} + +//======================================================================== +// Restore (un-iconify) the window +//======================================================================== + +void _glfwPlatformRestoreWindow( void ) +{ + [_glfwWin.window deminiaturize:nil]; +} + +//======================================================================== +// Swap buffers +//======================================================================== + +void _glfwPlatformSwapBuffers( void ) +{ + // ARP appears to be unnecessary, but this is future-proof + [_glfwWin.context flushBuffer]; +} + +//======================================================================== +// Set double buffering swap interval +//======================================================================== + +void _glfwPlatformSwapInterval( int interval ) +{ + GLint sync = interval; + [_glfwWin.context setValues:&sync forParameter:NSOpenGLCPSwapInterval]; +} + +//======================================================================== +// Write back window parameters into GLFW window structure +//======================================================================== + +void _glfwPlatformRefreshWindowParams( void ) +{ + GLint value; + + // Since GLFW 2.x doesn't understand screens, we use virtual screen zero + + [_glfwWin.pixelFormat getValues:&value + forAttribute:NSOpenGLPFAAccelerated + forVirtualScreen:0]; + _glfwWin.accelerated = value; + + [_glfwWin.pixelFormat getValues:&value + forAttribute:NSOpenGLPFAAlphaSize + forVirtualScreen:0]; + _glfwWin.alphaBits = value; + + // It seems that the color size includes the size of the alpha channel + [_glfwWin.pixelFormat getValues:&value + forAttribute:NSOpenGLPFAColorSize + forVirtualScreen:0]; + value -= _glfwWin.alphaBits; + _glfwWin.redBits = value / 3; + _glfwWin.greenBits = value / 3; + _glfwWin.blueBits = value / 3; + + [_glfwWin.pixelFormat getValues:&value + forAttribute:NSOpenGLPFADepthSize + forVirtualScreen:0]; + _glfwWin.depthBits = value; + + [_glfwWin.pixelFormat getValues:&value + forAttribute:NSOpenGLPFAStencilSize + forVirtualScreen:0]; + _glfwWin.stencilBits = value; + + [_glfwWin.pixelFormat getValues:&value + forAttribute:NSOpenGLPFAAccumSize + forVirtualScreen:0]; + _glfwWin.accumRedBits = value / 3; + _glfwWin.accumGreenBits = value / 3; + _glfwWin.accumBlueBits = value / 3; + + // TODO: Figure out what to set this value to + _glfwWin.accumAlphaBits = 0; + + [_glfwWin.pixelFormat getValues:&value + forAttribute:NSOpenGLPFAAuxBuffers + forVirtualScreen:0]; + _glfwWin.auxBuffers = value; + + [_glfwWin.pixelFormat getValues:&value + forAttribute:NSOpenGLPFAStereo + forVirtualScreen:0]; + _glfwWin.stereo = value; + + [_glfwWin.pixelFormat getValues:&value + forAttribute:NSOpenGLPFASamples + forVirtualScreen:0]; + _glfwWin.samples = value; + + // These are forced to false as long as Mac OS X lacks support for OpenGL 3.0+ + _glfwWin.glForward = GL_FALSE; + _glfwWin.glDebug = GL_FALSE; + _glfwWin.glProfile = 0; +} + +//======================================================================== +// Poll for new window and input events +//======================================================================== + +void _glfwPlatformPollEvents( void ) +{ + NSEvent *event; + + do + { + event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + + if (event) + { + [NSApp sendEvent:event]; + } + } + while (event); + + [_glfwLibrary.AutoreleasePool drain]; + _glfwLibrary.AutoreleasePool = [[NSAutoreleasePool alloc] init]; +} + +//======================================================================== +// Wait for new window and input events +//======================================================================== + +void _glfwPlatformWaitEvents( void ) +{ + // I wanted to pass NO to dequeue:, and rely on PollEvents to + // dequeue and send. For reasons not at all clear to me, passing + // NO to dequeue: causes this method never to return. + NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantFuture] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + [NSApp sendEvent:event]; + + _glfwPlatformPollEvents(); +} + +//======================================================================== +// Hide mouse cursor (lock it) +//======================================================================== + +void _glfwPlatformHideMouseCursor( void ) +{ + [NSCursor hide]; + CGAssociateMouseAndMouseCursorPosition( false ); +} + +//======================================================================== +// Show mouse cursor (unlock it) +//======================================================================== + +void _glfwPlatformShowMouseCursor( void ) +{ + [NSCursor unhide]; + CGAssociateMouseAndMouseCursorPosition( true ); +} + +//======================================================================== +// Set physical mouse cursor position +//======================================================================== + +void _glfwPlatformSetMouseCursorPos( int x, int y ) +{ + // The library seems to assume that after calling this the mouse won't move, + // but obviously it will, and escape the app's window, and activate other apps, + // and other badness in pain. I think the API's just silly, but maybe I'm + // misunderstanding it... + + // Also, (x, y) are window coords... + + // Also, it doesn't seem possible to write this robustly without + // calculating the maximum y coordinate of all screens, since Cocoa's + // "global coordinates" are upside down from CG's... + + // Without this (once per app run, but it's convenient to do it here) + // events will be suppressed for a default of 0.25 seconds after we + // move the cursor. + CGSetLocalEventsSuppressionInterval( 0.0 ); + + NSPoint localPoint = NSMakePoint( x, y ); + NSPoint globalPoint = [_glfwWin.window convertBaseToScreen:localPoint]; + CGPoint mainScreenOrigin = CGDisplayBounds( CGMainDisplayID() ).origin; + double mainScreenHeight = CGDisplayBounds( CGMainDisplayID() ).size.height; + CGPoint targetPoint = CGPointMake( globalPoint.x - mainScreenOrigin.x, + mainScreenHeight - globalPoint.y - mainScreenOrigin.y ); + CGDisplayMoveCursorToPoint( CGMainDisplayID(), targetPoint ); +} + diff --git a/lib/cocoa/libglfw.pc.cmake b/lib/cocoa/libglfw.pc.cmake new file mode 100644 index 00000000..2700c59d --- /dev/null +++ b/lib/cocoa/libglfw.pc.cmake @@ -0,0 +1,11 @@ +prefix=@PREFIX@ +exec_prefix=@PREFIX@ +libdir=@PREFIX@/lib +includedir=@PREFIX@/include + +Name: GLFW +Description: A portable framework for OpenGL development +Version: 2.7 +URL: http://glfw.sourceforge.net/ +Libs: -L${libdir} -lglfw -framework AGL -framework OpenGL -framework Carbon +Cflags: -I${includedir} diff --git a/lib/cocoa/platform.h b/lib/cocoa/platform.h new file mode 100644 index 00000000..844f0c4f --- /dev/null +++ b/lib/cocoa/platform.h @@ -0,0 +1,189 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Cocoa/NSOpenGL +// API Version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2009-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _platform_h_ +#define _platform_h_ + + +// This is the Mac OS X version of GLFW +#define _GLFW_MAC_OS_X + +#if defined(__OBJC__) +#import +#else +typedef void *id; +#endif + +#include "../../include/GL/glfw.h" + + +#ifndef GL_VERSION_3_0 + +typedef const GLubyte * (APIENTRY *PFNGLGETSTRINGIPROC) (GLenum, GLuint); + +#endif /*GL_VERSION_3_0*/ + + +//======================================================================== +// GLFW platform specific types +//======================================================================== + +//------------------------------------------------------------------------ +// Pointer length integer +//------------------------------------------------------------------------ +typedef intptr_t GLFWintptr; + +//------------------------------------------------------------------------ +// Window structure +//------------------------------------------------------------------------ +typedef struct _GLFWwin_struct _GLFWwin; + +struct _GLFWwin_struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // User callback functions + GLFWwindowsizefun windowSizeCallback; + GLFWwindowclosefun windowCloseCallback; + GLFWwindowrefreshfun windowRefreshCallback; + GLFWmousebuttonfun mouseButtonCallback; + GLFWmouseposfun mousePosCallback; + GLFWmousewheelfun mouseWheelCallback; + GLFWkeyfun keyCallback; + GLFWcharfun charCallback; + + // User selected window settings + int fullscreen; // Fullscreen flag + int mouseLock; // Mouse-lock flag + int autoPollEvents; // Auto polling flag + int sysKeysDisabled; // System keys disabled flag + int windowNoResize; // Resize- and maximize gadgets disabled flag + int refreshRate; // Vertical monitor refresh rate + + // Window status & parameters + int opened; // Flag telling if window is opened or not + int active; // Application active flag + int iconified; // Window iconified flag + int width, height; // Window width and heigth + int accelerated; // GL_TRUE if window is HW accelerated + + // Framebuffer attributes + int redBits; + int greenBits; + int blueBits; + int alphaBits; + int depthBits; + int stencilBits; + int accumRedBits; + int accumGreenBits; + int accumBlueBits; + int accumAlphaBits; + int auxBuffers; + int stereo; + int samples; + + // OpenGL extensions and context attributes + int has_GL_SGIS_generate_mipmap; + int has_GL_ARB_texture_non_power_of_two; + int glMajor, glMinor, glRevision; + int glForward, glDebug, glProfile; + + PFNGLGETSTRINGIPROC GetStringi; + +// ========= PLATFORM SPECIFIC PART ====================================== + + id window; + id pixelFormat; + id context; + id delegate; + unsigned int modifierFlags; +}; + +GLFWGLOBAL _GLFWwin _glfwWin; + + +//------------------------------------------------------------------------ +// Library global data +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Window opening hints + _GLFWhints hints; + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Timer data + struct { + double t0; + } Timer; + + // dlopen handle for dynamically-loading extension function pointers + void *OpenGLFramework; + + int Unbundled; + + id DesktopMode; + + id AutoreleasePool; + +} _glfwLibrary; + + +//------------------------------------------------------------------------ +// User input status (some of this should go in _GLFWwin) +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Mouse status + int MousePosX, MousePosY; + int WheelPos; + char MouseButton[ GLFW_MOUSE_BUTTON_LAST+1 ]; + + // Keyboard status + char Key[ GLFW_KEY_LAST+1 ]; + int LastChar; + + // User selected settings + int StickyKeys; + int StickyMouseButtons; + int KeyRepeat; + + +// ========= PLATFORM SPECIFIC PART ====================================== + + double WheelPosFloating; + +} _glfwInput; + + +#endif // _platform_h_ diff --git a/lib/enable.c b/lib/enable.c new file mode 100644 index 00000000..afafd89f --- /dev/null +++ b/lib/enable.c @@ -0,0 +1,310 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Any +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// Enable (show) mouse cursor +//======================================================================== + +static void enableMouseCursor( void ) +{ + int centerPosX, centerPosY; + + if( !_glfwWin.opened || !_glfwWin.mouseLock ) + { + return; + } + + // Show mouse cursor + _glfwPlatformShowMouseCursor(); + + centerPosX = _glfwWin.width / 2; + centerPosY = _glfwWin.height / 2; + + if( centerPosX != _glfwInput.MousePosX || centerPosY != _glfwInput.MousePosY ) + { + _glfwPlatformSetMouseCursorPos( centerPosX, centerPosY ); + + _glfwInput.MousePosX = centerPosX; + _glfwInput.MousePosY = centerPosY; + + if( _glfwWin.mousePosCallback ) + { + _glfwWin.mousePosCallback( _glfwInput.MousePosX, + _glfwInput.MousePosY ); + } + } + + // From now on the mouse is unlocked + _glfwWin.mouseLock = GL_FALSE; +} + +//======================================================================== +// Disable (hide) mouse cursor +//======================================================================== + +static void disableMouseCursor( void ) +{ + if( !_glfwWin.opened || _glfwWin.mouseLock ) + { + return; + } + + // Hide mouse cursor + _glfwPlatformHideMouseCursor(); + + // Move cursor to the middle of the window + _glfwPlatformSetMouseCursorPos( _glfwWin.width >> 1, + _glfwWin.height >> 1 ); + + // From now on the mouse is locked + _glfwWin.mouseLock = GL_TRUE; +} + + +//======================================================================== +// Enable sticky keys +//======================================================================== + +static void enableStickyKeys( void ) +{ + _glfwInput.StickyKeys = 1; +} + +//======================================================================== +// Disable sticky keys +//======================================================================== + +static void disableStickyKeys( void ) +{ + int i; + + _glfwInput.StickyKeys = 0; + + // Release all sticky keys + for( i = 0; i <= GLFW_KEY_LAST; i++ ) + { + if( _glfwInput.Key[ i ] == 2 ) + { + _glfwInput.Key[ i ] = 0; + } + } +} + + +//======================================================================== +// Enable sticky mouse buttons +//======================================================================== + +static void enableStickyMouseButtons( void ) +{ + _glfwInput.StickyMouseButtons = 1; +} + +//======================================================================== +// Disable sticky mouse buttons +//======================================================================== + +static void disableStickyMouseButtons( void ) +{ + int i; + + _glfwInput.StickyMouseButtons = 0; + + // Release all sticky mouse buttons + for( i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++ ) + { + if( _glfwInput.MouseButton[ i ] == 2 ) + { + _glfwInput.MouseButton[ i ] = 0; + } + } +} + + +//======================================================================== +// Enable system keys +//======================================================================== + +static void enableSystemKeys( void ) +{ + if( !_glfwWin.sysKeysDisabled ) + { + return; + } + + _glfwPlatformEnableSystemKeys(); + + // Indicate that system keys are no longer disabled + _glfwWin.sysKeysDisabled = GL_FALSE; +} + +//======================================================================== +// Disable system keys +//======================================================================== + +static void disableSystemKeys( void ) +{ + if( _glfwWin.sysKeysDisabled ) + { + return; + } + + _glfwPlatformDisableSystemKeys(); + + // Indicate that system keys are now disabled + _glfwWin.sysKeysDisabled = GL_TRUE; +} + + +//======================================================================== +// Enable key repeat +//======================================================================== + +static void enableKeyRepeat( void ) +{ + _glfwInput.KeyRepeat = 1; +} + +//======================================================================== +// Disable key repeat +//======================================================================== + +static void disableKeyRepeat( void ) +{ + _glfwInput.KeyRepeat = 0; +} + + +//======================================================================== +// Enable automatic event polling +//======================================================================== + +static void enableAutoPollEvents( void ) +{ + _glfwWin.autoPollEvents = 1; +} + +//======================================================================== +// Disable automatic event polling +//======================================================================== + +static void disableAutoPollEvents( void ) +{ + _glfwWin.autoPollEvents = 0; +} + + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// Enable certain GLFW/window/system functions. +//======================================================================== + +GLFWAPI void glfwEnable( int token ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return; + } + + switch( token ) + { + case GLFW_MOUSE_CURSOR: + enableMouseCursor(); + break; + case GLFW_STICKY_KEYS: + enableStickyKeys(); + break; + case GLFW_STICKY_MOUSE_BUTTONS: + enableStickyMouseButtons(); + break; + case GLFW_SYSTEM_KEYS: + enableSystemKeys(); + break; + case GLFW_KEY_REPEAT: + enableKeyRepeat(); + break; + case GLFW_AUTO_POLL_EVENTS: + enableAutoPollEvents(); + break; + default: + break; + } +} + + +//======================================================================== +// Disable certain GLFW/window/system functions. +//======================================================================== + +GLFWAPI void glfwDisable( int token ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return; + } + + switch( token ) + { + case GLFW_MOUSE_CURSOR: + disableMouseCursor(); + break; + case GLFW_STICKY_KEYS: + disableStickyKeys(); + break; + case GLFW_STICKY_MOUSE_BUTTONS: + disableStickyMouseButtons(); + break; + case GLFW_SYSTEM_KEYS: + disableSystemKeys(); + break; + case GLFW_KEY_REPEAT: + disableKeyRepeat(); + break; + case GLFW_AUTO_POLL_EVENTS: + disableAutoPollEvents(); + break; + default: + break; + } +} + diff --git a/lib/fullscreen.c b/lib/fullscreen.c new file mode 100644 index 00000000..0e363cc6 --- /dev/null +++ b/lib/fullscreen.c @@ -0,0 +1,94 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Any +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// glfwGetVideoModes() - Get a list of available video modes +//======================================================================== + +GLFWAPI int glfwGetVideoModes( GLFWvidmode *list, int maxcount ) +{ + int count, i, swap, res1, res2, depth1, depth2; + GLFWvidmode vm; + + if( !_glfwInitialized || maxcount <= 0 || list == (GLFWvidmode*) 0 ) + { + return 0; + } + + // Get list of video modes + count = _glfwPlatformGetVideoModes( list, maxcount ); + + // Sort list (bubble sort) + do + { + swap = 0; + for( i = 0; i < count-1; ++ i ) + { + res1 = list[i].Width*list[i].Height; + depth1 = list[i].RedBits+list[i].GreenBits+list[i].BlueBits; + res2 = list[i+1].Width*list[i+1].Height; + depth2 = list[i+1].RedBits+list[i+1].GreenBits+ + list[i+1].BlueBits; + if( (depth2 +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +#ifndef GL_VERSION_3_0 +#define GL_NUM_EXTENSIONS 0x821D +#endif + +//======================================================================== +// Parses the OpenGL version string and extracts the version number +//======================================================================== + +void _glfwParseGLVersion( int *major, int *minor, int *rev ) +{ + GLuint _major, _minor = 0, _rev = 0; + const GLubyte *version; + const GLubyte *ptr; + + // Get OpenGL version string + version = glGetString( GL_VERSION ); + if( !version ) + { + return; + } + + // Parse string + ptr = version; + for( _major = 0; *ptr >= '0' && *ptr <= '9'; ptr ++ ) + { + _major = 10*_major + (*ptr - '0'); + } + if( *ptr == '.' ) + { + ptr ++; + for( _minor = 0; *ptr >= '0' && *ptr <= '9'; ptr ++ ) + { + _minor = 10*_minor + (*ptr - '0'); + } + if( *ptr == '.' ) + { + ptr ++; + for( _rev = 0; *ptr >= '0' && *ptr <= '9'; ptr ++ ) + { + _rev = 10*_rev + (*ptr - '0'); + } + } + } + + // Return parsed values + *major = _major; + *minor = _minor; + *rev = _rev; +} + +//======================================================================== +// _glfwStringInExtensionString() - Check if a string can be found in an +// OpenGL extension string +//======================================================================== + +int _glfwStringInExtensionString( const char *string, + const GLubyte *extensions ) +{ + const GLubyte *start; + GLubyte *where, *terminator; + + // It takes a bit of care to be fool-proof about parsing the + // OpenGL extensions string. Don't be fooled by sub-strings, + // etc. + start = extensions; + while( 1 ) + { + where = (GLubyte *) strstr( (const char *) start, string ); + if( !where ) + { + return GL_FALSE; + } + terminator = where + strlen( string ); + if( where == start || *(where - 1) == ' ' ) + { + if( *terminator == ' ' || *terminator == '\0' ) + { + break; + } + } + start = terminator; + } + + return GL_TRUE; +} + + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// Check if an OpenGL extension is available at runtime +//======================================================================== + +GLFWAPI int glfwExtensionSupported( const char *extension ) +{ + const GLubyte *extensions; + GLubyte *where; + GLint count; + int i; + + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return GL_FALSE; + } + + // Extension names should not have spaces + where = (GLubyte *) strchr( extension, ' ' ); + if( where || *extension == '\0' ) + { + return GL_FALSE; + } + + if( _glfwWin.glMajor < 3 ) + { + // Check if extension is in the old style OpenGL extensions string + + extensions = glGetString( GL_EXTENSIONS ); + if( extensions != NULL ) + { + if( _glfwStringInExtensionString( extension, extensions ) ) + { + return GL_TRUE; + } + } + } + else + { + // Check if extension is in the modern OpenGL extensions string list + + glGetIntegerv( GL_NUM_EXTENSIONS, &count ); + + for( i = 0; i < count; i++ ) + { + if( strcmp( (const char*) _glfwWin.GetStringi( GL_EXTENSIONS, i ), + extension ) == 0 ) + { + return GL_TRUE; + } + } + } + + // Additional platform specific extension checking (e.g. WGL) + if( _glfwPlatformExtensionSupported( extension ) ) + { + return GL_TRUE; + } + + return GL_FALSE; +} + + +//======================================================================== +// glfwGetProcAddress() - Get the function pointer to an OpenGL function. +// This function can be used to get access to extended OpenGL functions. +//======================================================================== + +GLFWAPI void * glfwGetProcAddress( const char *procname ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return NULL; + } + + return _glfwPlatformGetProcAddress( procname ); +} + + +//======================================================================== +// Returns the OpenGL version +//======================================================================== + +GLFWAPI void glfwGetGLVersion( int *major, int *minor, int *rev ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + if( major != NULL ) + { + *major = _glfwWin.glMajor; + } + if( minor != NULL ) + { + *minor = _glfwWin.glMinor; + } + if( rev != NULL ) + { + *rev = _glfwWin.glRevision; + } +} + diff --git a/lib/init.c b/lib/init.c new file mode 100644 index 00000000..f3d3dee7 --- /dev/null +++ b/lib/init.c @@ -0,0 +1,110 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Any +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#define _init_c_ +#include "internal.h" + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// glfwInit() - Initialize various GLFW state +//======================================================================== + +GLFWAPI int glfwInit( void ) +{ + // Is GLFW already initialized? + if( _glfwInitialized ) + { + return GL_TRUE; + } + + memset( &_glfwLibrary, 0, sizeof( _glfwLibrary ) ); + memset( &_glfwWin, 0, sizeof( _glfwWin ) ); + + // Window is not yet opened + _glfwWin.opened = GL_FALSE; + + // Default enable/disable settings + _glfwWin.sysKeysDisabled = GL_FALSE; + + // Clear window hints + _glfwClearWindowHints(); + + // Platform specific initialization + if( !_glfwPlatformInit() ) + { + return GL_FALSE; + } + + // Form now on, GLFW state is valid + _glfwInitialized = GL_TRUE; + + return GL_TRUE; +} + + + +//======================================================================== +// Close window and shut down library +//======================================================================== + +GLFWAPI void glfwTerminate( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return; + } + + // Platform specific termination + if( !_glfwPlatformTerminate() ) + { + return; + } + + // GLFW is no longer initialized + _glfwInitialized = GL_FALSE; +} + + +//======================================================================== +// glfwGetVersion() - Get GLFW version +//======================================================================== + +GLFWAPI void glfwGetVersion( int *major, int *minor, int *rev ) +{ + if( major != NULL ) *major = GLFW_VERSION_MAJOR; + if( minor != NULL ) *minor = GLFW_VERSION_MINOR; + if( rev != NULL ) *rev = GLFW_VERSION_REVISION; +} + diff --git a/lib/input.c b/lib/input.c new file mode 100644 index 00000000..faf47cc2 --- /dev/null +++ b/lib/input.c @@ -0,0 +1,280 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Any +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +//======================================================================== +// glfwGetKey() +//======================================================================== + +GLFWAPI int glfwGetKey( int key ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return GLFW_RELEASE; + } + + // Is it a valid key? + if( key < 0 || key > GLFW_KEY_LAST ) + { + return GLFW_RELEASE; + } + + if( _glfwInput.Key[ key ] == GLFW_STICK ) + { + // Sticky mode: release key now + _glfwInput.Key[ key ] = GLFW_RELEASE; + return GLFW_PRESS; + } + + return (int) _glfwInput.Key[ key ]; +} + + +//======================================================================== +// glfwGetMouseButton() +//======================================================================== + +GLFWAPI int glfwGetMouseButton( int button ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return GLFW_RELEASE; + } + + // Is it a valid mouse button? + if( button < 0 || button > GLFW_MOUSE_BUTTON_LAST ) + { + return GLFW_RELEASE; + } + + if( _glfwInput.MouseButton[ button ] == GLFW_STICK ) + { + // Sticky mode: release mouse button now + _glfwInput.MouseButton[ button ] = GLFW_RELEASE; + return GLFW_PRESS; + } + + return (int) _glfwInput.MouseButton[ button ]; +} + + +//======================================================================== +// glfwGetMousePos() +//======================================================================== + +GLFWAPI void glfwGetMousePos( int *xpos, int *ypos ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + // Return mouse position + if( xpos != NULL ) + { + *xpos = _glfwInput.MousePosX; + } + if( ypos != NULL ) + { + *ypos = _glfwInput.MousePosY; + } +} + + +//======================================================================== +// glfwSetMousePos() +//======================================================================== + +GLFWAPI void glfwSetMousePos( int xpos, int ypos ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + // Don't do anything if the mouse position did not change + if( xpos == _glfwInput.MousePosX && ypos == _glfwInput.MousePosY ) + { + return; + } + + // Set GLFW mouse position + _glfwInput.MousePosX = xpos; + _glfwInput.MousePosY = ypos; + + // If we have a locked mouse, do not change cursor position + if( _glfwWin.mouseLock ) + { + return; + } + + // Update physical cursor position + _glfwPlatformSetMouseCursorPos( xpos, ypos ); +} + + +//======================================================================== +// glfwGetMouseWheel() +//======================================================================== + +GLFWAPI int glfwGetMouseWheel( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return 0; + } + + // Return mouse wheel position + return _glfwInput.WheelPos; +} + + +//======================================================================== +// glfwSetMouseWheel() +//======================================================================== + +GLFWAPI void glfwSetMouseWheel( int pos ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + // Set mouse wheel position + _glfwInput.WheelPos = pos; +} + + +//======================================================================== +// glfwSetKeyCallback() - Set callback function for keyboard input +//======================================================================== + +GLFWAPI void glfwSetKeyCallback( GLFWkeyfun cbfun ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + // Set callback function + _glfwWin.keyCallback = cbfun; +} + + +//======================================================================== +// glfwSetCharCallback() - Set callback function for character input +//======================================================================== + +GLFWAPI void glfwSetCharCallback( GLFWcharfun cbfun ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + // Set callback function + _glfwWin.charCallback = cbfun; +} + + +//======================================================================== +// glfwSetMouseButtonCallback() - Set callback function for mouse clicks +//======================================================================== + +GLFWAPI void glfwSetMouseButtonCallback( GLFWmousebuttonfun cbfun ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + // Set callback function + _glfwWin.mouseButtonCallback = cbfun; +} + + +//======================================================================== +// glfwSetMousePosCallback() - Set callback function for mouse moves +//======================================================================== + +GLFWAPI void glfwSetMousePosCallback( GLFWmouseposfun cbfun ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + // Set callback function + _glfwWin.mousePosCallback = cbfun; + + // Call the callback function to let the application know the current + // mouse position + if( cbfun ) + { + cbfun( _glfwInput.MousePosX, _glfwInput.MousePosY ); + } +} + + +//======================================================================== +// glfwSetMouseWheelCallback() - Set callback function for mouse wheel +//======================================================================== + +GLFWAPI void glfwSetMouseWheelCallback( GLFWmousewheelfun cbfun ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + // Set callback function + _glfwWin.mouseWheelCallback = cbfun; + + // Call the callback function to let the application know the current + // mouse wheel position + if( cbfun ) + { + cbfun( _glfwInput.WheelPos ); + } +} + diff --git a/lib/internal.h b/lib/internal.h new file mode 100644 index 00000000..3aeb081a --- /dev/null +++ b/lib/internal.h @@ -0,0 +1,221 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Any +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _internal_h_ +#define _internal_h_ + +//======================================================================== +// GLFWGLOBAL is a macro that places all global variables in the init.c +// module (all other modules reference global variables as 'extern') +//======================================================================== + +#if defined( _init_c_ ) +#define GLFWGLOBAL +#else +#define GLFWGLOBAL extern +#endif + + +//======================================================================== +// Input handling definitions +//======================================================================== + +// Internal key and button state/action definitions +#define GLFW_STICK 2 + + +//======================================================================== +// System independent include files +//======================================================================== + +#include +#include +#include + + +//------------------------------------------------------------------------ +// Window opening hints (set by glfwOpenWindowHint) +// A bucket of semi-random stuff bunched together for historical reasons +// This is used only by the platform independent code and only to store +// parameters passed to us by glfwOpenWindowHint +//------------------------------------------------------------------------ +typedef struct { + int refreshRate; + int accumRedBits; + int accumGreenBits; + int accumBlueBits; + int accumAlphaBits; + int auxBuffers; + int stereo; + int windowNoResize; + int samples; + int glMajor; + int glMinor; + int glForward; + int glDebug; + int glProfile; +} _GLFWhints; + + +//------------------------------------------------------------------------ +// Platform specific definitions goes in platform.h (which also includes +// glfw.h) +//------------------------------------------------------------------------ + +#include "platform.h" + + +//------------------------------------------------------------------------ +// Parameters relating to the creation of the context and window but not +// directly related to the properties of the framebuffer +// This is used to pass window and context creation parameters from the +// platform independent code to the platform specific code +//------------------------------------------------------------------------ +typedef struct { + int mode; + int refreshRate; + int windowNoResize; + int glMajor; + int glMinor; + int glForward; + int glDebug; + int glProfile; +} _GLFWwndconfig; + + +//------------------------------------------------------------------------ +// Framebuffer configuration descriptor, i.e. buffers and their sizes +// Also a platform specific ID used to map back to the actual backend APIs +// This is used to pass framebuffer parameters from the platform independent +// code to the platform specific code, and also to enumerate and select +// available framebuffer configurations +//------------------------------------------------------------------------ +typedef struct { + int redBits; + int greenBits; + int blueBits; + int alphaBits; + int depthBits; + int stencilBits; + int accumRedBits; + int accumGreenBits; + int accumBlueBits; + int accumAlphaBits; + int auxBuffers; + int stereo; + int samples; + GLFWintptr platformID; +} _GLFWfbconfig; + + +//======================================================================== +// System independent global variables (GLFW internals) +//======================================================================== + +// Flag indicating if GLFW has been initialized +#if defined( _init_c_ ) +int _glfwInitialized = 0; +#else +GLFWGLOBAL int _glfwInitialized; +#endif + + +//======================================================================== +// Prototypes for platform specific implementation functions +//======================================================================== + +// Init/terminate +int _glfwPlatformInit( void ); +int _glfwPlatformTerminate( void ); + +// Enable/Disable +void _glfwPlatformEnableSystemKeys( void ); +void _glfwPlatformDisableSystemKeys( void ); + +// Fullscreen +int _glfwPlatformGetVideoModes( GLFWvidmode *list, int maxcount ); +void _glfwPlatformGetDesktopMode( GLFWvidmode *mode ); + +// OpenGL extensions +int _glfwPlatformExtensionSupported( const char *extension ); +void * _glfwPlatformGetProcAddress( const char *procname ); + +// Joystick +int _glfwPlatformGetJoystickParam( int joy, int param ); +int _glfwPlatformGetJoystickPos( int joy, float *pos, int numaxes ); +int _glfwPlatformGetJoystickButtons( int joy, unsigned char *buttons, int numbuttons ); + +// Time +double _glfwPlatformGetTime( void ); +void _glfwPlatformSetTime( double time ); + +// Window management +int _glfwPlatformOpenWindow( int width, int height, const _GLFWwndconfig *wndconfig, const _GLFWfbconfig *fbconfig ); +void _glfwPlatformCloseWindow( void ); +void _glfwPlatformSetWindowTitle( const char *title ); +void _glfwPlatformSetWindowSize( int width, int height ); +void _glfwPlatformSetWindowPos( int x, int y ); +void _glfwPlatformIconifyWindow( void ); +void _glfwPlatformRestoreWindow( void ); +void _glfwPlatformSwapBuffers( void ); +void _glfwPlatformSwapInterval( int interval ); +void _glfwPlatformRefreshWindowParams( void ); +void _glfwPlatformPollEvents( void ); +void _glfwPlatformWaitEvents( void ); +void _glfwPlatformHideMouseCursor( void ); +void _glfwPlatformShowMouseCursor( void ); +void _glfwPlatformSetMouseCursorPos( int x, int y ); + + +//======================================================================== +// Prototypes for platform independent internal functions +//======================================================================== + +// Window management (window.c) +void _glfwClearWindowHints( void ); + +// Input handling (window.c) +void _glfwClearInput( void ); +void _glfwInputDeactivation( void ); +void _glfwInputKey( int key, int action ); +void _glfwInputChar( int character, int action ); +void _glfwInputMouseClick( int button, int action ); + +// OpenGL extensions (glext.c) +void _glfwParseGLVersion( int *major, int *minor, int *rev ); +int _glfwStringInExtensionString( const char *string, const GLubyte *extensions ); + +// Framebuffer configs +const _GLFWfbconfig *_glfwChooseFBConfig( const _GLFWfbconfig *desired, + const _GLFWfbconfig *alternatives, + unsigned int count ); + + +#endif // _internal_h_ diff --git a/lib/joystick.c b/lib/joystick.c new file mode 100644 index 00000000..32841a75 --- /dev/null +++ b/lib/joystick.c @@ -0,0 +1,102 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Any +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// glfwGetJoystickParam() - Determine joystick capabilities +//======================================================================== + +GLFWAPI int glfwGetJoystickParam( int joy, int param ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return 0; + } + + return _glfwPlatformGetJoystickParam( joy, param ); +} + + +//======================================================================== +// glfwGetJoystickPos() - Get joystick axis positions +//======================================================================== + +GLFWAPI int glfwGetJoystickPos( int joy, float *pos, int numaxes ) +{ + int i; + + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return 0; + } + + // Clear positions + for( i = 0; i < numaxes; i++ ) + { + pos[ i ] = 0.0f; + } + + return _glfwPlatformGetJoystickPos( joy, pos, numaxes ); +} + + +//======================================================================== +// glfwGetJoystickButtons() - Get joystick button states +//======================================================================== + +GLFWAPI int glfwGetJoystickButtons( int joy, + unsigned char *buttons, + int numbuttons ) +{ + int i; + + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return 0; + } + + // Clear button states + for( i = 0; i < numbuttons; i++ ) + { + buttons[ i ] = GLFW_RELEASE; + } + + return _glfwPlatformGetJoystickButtons( joy, buttons, numbuttons ); +} + diff --git a/lib/time.c b/lib/time.c new file mode 100644 index 00000000..f7ea31c5 --- /dev/null +++ b/lib/time.c @@ -0,0 +1,68 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Any +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// glfwGetTime() - Return timer value in seconds +//======================================================================== + +GLFWAPI double glfwGetTime( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return 0.0; + } + + return _glfwPlatformGetTime(); +} + + +//======================================================================== +// glfwSetTime() - Set timer value in seconds +//======================================================================== + +GLFWAPI void glfwSetTime( double time ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return; + } + + _glfwPlatformSetTime( time ); +} + diff --git a/lib/win32/CMakeLists.txt b/lib/win32/CMakeLists.txt new file mode 100644 index 00000000..d5230c68 --- /dev/null +++ b/lib/win32/CMakeLists.txt @@ -0,0 +1,55 @@ + +if(CYGWIN) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/libglfw.pc.cmake + ${CMAKE_CURRENT_BINARY_DIR}/libglfw.pc @ONLY) + +# These lines are intended to remove the --export-all-symbols +# flag added in the Modules/Platform/CYGWIN.cmake file of the +# CMake distribution. +# This is a HACK. If you have trouble _linking_ the GLFW +# _shared_ library on Cygwin, try disabling this. + set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared") + set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS}) + +endif(CYGWIN) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/lib) + +set(libglfw_SOURCES + ${common_SOURCES} + win32_enable.c + win32_fullscreen.c + win32_glext.c + win32_init.c + win32_joystick.c + win32_time.c + win32_window.c + win32_dllmain.c) + +add_library(libglfwStatic STATIC ${libglfw_SOURCES}) +add_library(libglfwShared SHARED glfwdll.def ${libglfw_SOURCES}) + +target_link_libraries(libglfwShared ${OPENGL_gl_LIBRARY}) +set_target_properties(libglfwShared PROPERTIES + DEFINE_SYMBOL GLFW_BUILD_DLL + PREFIX "" + IMPORT_PREFIX "" + IMPORT_SUFFIX "dll.lib") + +set_target_properties(libglfwStatic libglfwShared PROPERTIES + CLEAN_DIRECT_OUTPUT 1 + OUTPUT_NAME glfw) + +if(CYGWIN) + # Build for the regular Win32 environment (not Cygwin) + set_target_properties(libglfwStatic libglfwShared PROPERTIES COMPILE_FLAGS "-mwin32 -mno-cygwin") + set_target_properties(libglfwStatic libglfwShared PROPERTIES LINK_FLAGS "-mwin32 -mno-cygwin") +endif(CYGWIN) + +install(TARGETS libglfwStatic libglfwShared DESTINATION lib) + +if(CYGWIN) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libglfw.pc DESTINATION lib/pkgconfig) +endif(CYGWIN) + diff --git a/lib/win32/glfwdll.def b/lib/win32/glfwdll.def new file mode 100644 index 00000000..4f4ce470 --- /dev/null +++ b/lib/win32/glfwdll.def @@ -0,0 +1,46 @@ +LIBRARY GLFW.DLL + +EXPORTS +glfwCloseWindow +glfwDisable +glfwEnable +glfwExtensionSupported +glfwGetDesktopMode +glfwGetGLVersion +glfwGetJoystickButtons +glfwGetJoystickParam +glfwGetJoystickPos +glfwGetKey +glfwGetMouseButton +glfwGetMousePos +glfwGetMouseWheel +glfwGetProcAddress +glfwGetTime +glfwGetVersion +glfwGetVideoModes +glfwGetWindowParam +glfwGetWindowSize +glfwIconifyWindow +glfwInit +glfwOpenWindow +glfwOpenWindowHint +glfwPollEvents +glfwRestoreWindow +glfwSetCharCallback +glfwSetKeyCallback +glfwSetMouseButtonCallback +glfwSetMousePos +glfwSetMousePosCallback +glfwSetMouseWheel +glfwSetMouseWheelCallback +glfwSetTime +glfwSetWindowCloseCallback +glfwSetWindowRefreshCallback +glfwSetWindowPos +glfwSetWindowSize +glfwSetWindowSizeCallback +glfwSetWindowTitle +glfwSwapBuffers +glfwSwapInterval +glfwTerminate +glfwWaitEvents diff --git a/lib/win32/glfwdll_mgw1.def b/lib/win32/glfwdll_mgw1.def new file mode 100644 index 00000000..bdf475f2 --- /dev/null +++ b/lib/win32/glfwdll_mgw1.def @@ -0,0 +1,46 @@ +LIBRARY GLFW.DLL + +EXPORTS +glfwCloseWindow = glfwCloseWindow@0 +glfwDisable = glfwDisable@4 +glfwEnable = glfwEnable@4 +glfwExtensionSupported = glfwExtensionSupported@4 +glfwGetDesktopMode = glfwGetDesktopMode@4 +glfwGetGLVersion = glfwGetGLVersion@12 +glfwGetJoystickButtons = glfwGetJoystickButtons@12 +glfwGetJoystickParam = glfwGetJoystickParam@8 +glfwGetJoystickPos = glfwGetJoystickPos@12 +glfwGetKey = glfwGetKey@4 +glfwGetMouseButton = glfwGetMouseButton@4 +glfwGetMousePos = glfwGetMousePos@8 +glfwGetMouseWheel = glfwGetMouseWheel@0 +glfwGetProcAddress = glfwGetProcAddress@4 +glfwGetTime = glfwGetTime@0 +glfwGetVersion = glfwGetVersion@12 +glfwGetVideoModes = glfwGetVideoModes@8 +glfwGetWindowParam = glfwGetWindowParam@4 +glfwGetWindowSize = glfwGetWindowSize@8 +glfwIconifyWindow = glfwIconifyWindow@0 +glfwInit = glfwInit@0 +glfwOpenWindow = glfwOpenWindow@36 +glfwOpenWindowHint = glfwOpenWindowHint@8 +glfwPollEvents = glfwPollEvents@0 +glfwRestoreWindow = glfwRestoreWindow@0 +glfwSetCharCallback = glfwSetCharCallback@4 +glfwSetKeyCallback = glfwSetKeyCallback@4 +glfwSetMouseButtonCallback = glfwSetMouseButtonCallback@4 +glfwSetMousePos = glfwSetMousePos@8 +glfwSetMousePosCallback = glfwSetMousePosCallback@4 +glfwSetMouseWheel = glfwSetMouseWheel@4 +glfwSetMouseWheelCallback = glfwSetMouseWheelCallback@4 +glfwSetTime = glfwSetTime@8 +glfwSetWindowCloseCallback = glfwSetWindowCloseCallback@4 +glfwSetWindowRefreshCallback = glfwSetWindowRefreshCallback@4 +glfwSetWindowPos = glfwSetWindowPos@8 +glfwSetWindowSize = glfwSetWindowSize@8 +glfwSetWindowSizeCallback = glfwSetWindowSizeCallback@4 +glfwSetWindowTitle = glfwSetWindowTitle@4 +glfwSwapBuffers = glfwSwapBuffers@0 +glfwSwapInterval = glfwSwapInterval@4 +glfwTerminate = glfwTerminate@0 +glfwWaitEvents = glfwWaitEvents@0 diff --git a/lib/win32/glfwdll_mgw2.def b/lib/win32/glfwdll_mgw2.def new file mode 100644 index 00000000..2a2b6ce1 --- /dev/null +++ b/lib/win32/glfwdll_mgw2.def @@ -0,0 +1,46 @@ +LIBRARY GLFW.DLL + +EXPORTS +glfwCloseWindow@0 +glfwDisable@4 +glfwEnable@4 +glfwExtensionSupported@4 +glfwGetDesktopMode@4 +glfwGetGLVersion@12 +glfwGetJoystickButtons@12 +glfwGetJoystickParam@8 +glfwGetJoystickPos@12 +glfwGetKey@4 +glfwGetMouseButton@4 +glfwGetMousePos@8 +glfwGetMouseWheel@0 +glfwGetProcAddress@4 +glfwGetTime@0 +glfwGetVersion@12 +glfwGetVideoModes@8 +glfwGetWindowParam@4 +glfwGetWindowSize@8 +glfwIconifyWindow@0 +glfwInit@0 +glfwOpenWindow@36 +glfwOpenWindowHint@8 +glfwPollEvents@0 +glfwRestoreWindow@0 +glfwSetCharCallback@4 +glfwSetKeyCallback@4 +glfwSetMouseButtonCallback@4 +glfwSetMousePos@8 +glfwSetMousePosCallback@4 +glfwSetMouseWheel@4 +glfwSetMouseWheelCallback@4 +glfwSetTime@8 +glfwSetWindowCloseCallback@4 +glfwSetWindowRefreshCallback@4 +glfwSetWindowPos@8 +glfwSetWindowSize@8 +glfwSetWindowSizeCallback@4 +glfwSetWindowTitle@4 +glfwSwapBuffers@0 +glfwSwapInterval@4 +glfwTerminate@0 +glfwWaitEvents@0 diff --git a/lib/win32/libglfw.pc.cmake b/lib/win32/libglfw.pc.cmake new file mode 100644 index 00000000..684b4ba2 --- /dev/null +++ b/lib/win32/libglfw.pc.cmake @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: GLFW +Description: A portable framework for OpenGL development +Version: 2.7 +URL: http://glfw.sourceforge.net/ +Libs: -L${libdir} -lglfw @GLFW_LIBRARIES@ +Cflags: -I${includedir} -mwin32 diff --git a/lib/win32/platform.h b/lib/win32/platform.h new file mode 100644 index 00000000..46cef336 --- /dev/null +++ b/lib/win32/platform.h @@ -0,0 +1,480 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Win32/WGL +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _platform_h_ +#define _platform_h_ + + +// This is the Windows version of GLFW +#define _GLFW_WIN32 + +// We don't need all the fancy stuff +#define NOMINMAX +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRALEAN + +// Include files +#include +#include +#include "../../include/GL/glfw.h" + + +//======================================================================== +// Hack: Define things that some 's do not define +//======================================================================== + +// Some old versions of w32api (used by MinGW and Cygwin) define +// WH_KEYBOARD_LL without typedef:ing KBDLLHOOKSTRUCT (!) +#if defined(__MINGW32__) || defined(__CYGWIN__) +#include +#if defined(WH_KEYBOARD_LL) && (__W32API_MAJOR_VERSION == 1) && (__W32API_MINOR_VERSION <= 2) +#undef WH_KEYBOARD_LL +#endif +#endif + +//------------------------------------------------------------------------ +// ** NOTE ** If this gives you compiler errors and you are using MinGW +// (or Dev-C++), update to w32api version 1.3 or later: +// http://sourceforge.net/project/showfiles.php?group_id=2435 +//------------------------------------------------------------------------ +#ifndef WH_KEYBOARD_LL +#define WH_KEYBOARD_LL 13 +typedef struct tagKBDLLHOOKSTRUCT { + DWORD vkCode; + DWORD scanCode; + DWORD flags; + DWORD time; + DWORD dwExtraInfo; +} KBDLLHOOKSTRUCT, FAR *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT; +#endif // WH_KEYBOARD_LL + +#ifndef LLKHF_ALTDOWN +#define LLKHF_ALTDOWN 0x00000020 +#endif + +#ifndef SPI_SETSCREENSAVERRUNNING +#define SPI_SETSCREENSAVERRUNNING 97 +#endif +#ifndef SPI_GETANIMATION +#define SPI_GETANIMATION 72 +#endif +#ifndef SPI_SETANIMATION +#define SPI_SETANIMATION 73 +#endif +#ifndef SPI_GETFOREGROUNDLOCKTIMEOUT +#define SPI_GETFOREGROUNDLOCKTIMEOUT 0x2000 +#endif +#ifndef SPI_SETFOREGROUNDLOCKTIMEOUT +#define SPI_SETFOREGROUNDLOCKTIMEOUT 0x2001 +#endif + +#ifndef CDS_FULLSCREEN +#define CDS_FULLSCREEN 4 +#endif + +#ifndef PFD_GENERIC_ACCELERATED +#define PFD_GENERIC_ACCELERATED 0x00001000 +#endif +#ifndef PFD_DEPTH_DONTCARE +#define PFD_DEPTH_DONTCARE 0x20000000 +#endif + +#ifndef ENUM_CURRENT_SETTINGS +#define ENUM_CURRENT_SETTINGS -1 +#endif +#ifndef ENUM_REGISTRY_SETTINGS +#define ENUM_REGISTRY_SETTINGS -2 +#endif + +#ifndef WM_MOUSEWHEEL +#define WM_MOUSEWHEEL 0x020A +#endif +#ifndef WHEEL_DELTA +#define WHEEL_DELTA 120 +#endif + +#ifndef WM_XBUTTONDOWN +#define WM_XBUTTONDOWN 0x020B +#endif +#ifndef WM_XBUTTONUP +#define WM_XBUTTONUP 0x020C +#endif +#ifndef XBUTTON1 +#define XBUTTON1 1 +#endif +#ifndef XBUTTON2 +#define XBUTTON2 2 +#endif + +#ifndef WGL_ARB_pixel_format + +// wglSwapIntervalEXT typedef (Win32 buffer-swap interval control) +typedef int (APIENTRY * WGLSWAPINTERVALEXT_T) (int); +// wglGetPixelFormatAttribivARB typedef +typedef BOOL (WINAPI * WGLGETPIXELFORMATATTRIBIVARB_T) (HDC, int, int, UINT, const int *, int *); +// wglGetExtensionStringEXT typedef +typedef const char *(APIENTRY * WGLGETEXTENSIONSSTRINGEXT_T)( void ); +// wglGetExtensionStringARB typedef +typedef const char *(APIENTRY * WGLGETEXTENSIONSSTRINGARB_T)( HDC ); + +/* Constants for wglGetPixelFormatAttribivARB */ +#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_STEREO_ARB 0x2012 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_ACCUM_BITS_ARB 0x201D +#define WGL_ACCUM_RED_BITS_ARB 0x201E +#define WGL_ACCUM_GREEN_BITS_ARB 0x201F +#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_AUX_BUFFERS_ARB 0x2024 +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 + +/* Constants for WGL_ACCELERATION_ARB */ +#define WGL_NO_ACCELERATION_ARB 0x2025 +#define WGL_GENERIC_ACCELERATION_ARB 0x2026 +#define WGL_FULL_ACCELERATION_ARB 0x2027 + +/* Constants for WGL_PIXEL_TYPE_ARB */ +#define WGL_TYPE_RGBA_ARB 0x202B +#define WGL_TYPE_COLORINDEX_ARB 0x202C + +#endif /*WGL_ARB_pixel_format*/ + + +#ifndef WGL_ARB_create_context + +/* wglCreateContextAttribsARB */ +typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC, HGLRC, const int *); + +/* Tokens for wglCreateContextAttribsARB attributes */ +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 + +/* Bits for WGL_CONTEXT_FLAGS_ARB */ +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 + +/* Bits for WGL_CONTEXT_PROFILE_MASK_ARB */ +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 + +#endif /*WGL_ARB_create_context*/ + + +#ifndef GL_VERSION_3_0 + +typedef const GLubyte * (APIENTRY *PFNGLGETSTRINGIPROC) (GLenum, GLuint); + +#endif /*GL_VERSION_3_0*/ + + +//======================================================================== +// DLLs that are loaded at glfwInit() +//======================================================================== + +// gdi32.dll function pointer typedefs +#ifndef _GLFW_NO_DLOAD_GDI32 +typedef int (WINAPI * CHOOSEPIXELFORMAT_T) (HDC,CONST PIXELFORMATDESCRIPTOR*); +typedef int (WINAPI * DESCRIBEPIXELFORMAT_T) (HDC,int,UINT,LPPIXELFORMATDESCRIPTOR); +typedef int (WINAPI * GETPIXELFORMAT_T) (HDC); +typedef BOOL (WINAPI * SETPIXELFORMAT_T) (HDC,int,const PIXELFORMATDESCRIPTOR*); +typedef BOOL (WINAPI * SWAPBUFFERS_T) (HDC); +#endif // _GLFW_NO_DLOAD_GDI32 + +// winmm.dll function pointer typedefs +#ifndef _GLFW_NO_DLOAD_WINMM +typedef MMRESULT (WINAPI * JOYGETDEVCAPSA_T) (UINT,LPJOYCAPSA,UINT); +typedef MMRESULT (WINAPI * JOYGETPOS_T) (UINT,LPJOYINFO); +typedef MMRESULT (WINAPI * JOYGETPOSEX_T) (UINT,LPJOYINFOEX); +typedef DWORD (WINAPI * TIMEGETTIME_T) (void); +#endif // _GLFW_NO_DLOAD_WINMM + + +// gdi32.dll shortcuts +#ifndef _GLFW_NO_DLOAD_GDI32 +#define _glfw_ChoosePixelFormat _glfwLibrary.Libs.ChoosePixelFormat +#define _glfw_DescribePixelFormat _glfwLibrary.Libs.DescribePixelFormat +#define _glfw_GetPixelFormat _glfwLibrary.Libs.GetPixelFormat +#define _glfw_SetPixelFormat _glfwLibrary.Libs.SetPixelFormat +#define _glfw_SwapBuffers _glfwLibrary.Libs.SwapBuffers +#else +#define _glfw_ChoosePixelFormat ChoosePixelFormat +#define _glfw_DescribePixelFormat DescribePixelFormat +#define _glfw_GetPixelFormat GetPixelFormat +#define _glfw_SetPixelFormat SetPixelFormat +#define _glfw_SwapBuffers SwapBuffers +#endif // _GLFW_NO_DLOAD_GDI32 + +// winmm.dll shortcuts +#ifndef _GLFW_NO_DLOAD_WINMM +#define _glfw_joyGetDevCaps _glfwLibrary.Libs.joyGetDevCapsA +#define _glfw_joyGetPos _glfwLibrary.Libs.joyGetPos +#define _glfw_joyGetPosEx _glfwLibrary.Libs.joyGetPosEx +#define _glfw_timeGetTime _glfwLibrary.Libs.timeGetTime +#else +#define _glfw_joyGetDevCaps joyGetDevCapsA +#define _glfw_joyGetPos joyGetPos +#define _glfw_joyGetPosEx joyGetPosEx +#define _glfw_timeGetTime timeGetTime +#endif // _GLFW_NO_DLOAD_WINMM + + +//======================================================================== +// GLFW platform specific types +//======================================================================== + +//------------------------------------------------------------------------ +// Pointer length integer +//------------------------------------------------------------------------ +typedef INT_PTR GLFWintptr; + + +//------------------------------------------------------------------------ +// Window structure +//------------------------------------------------------------------------ +typedef struct _GLFWwin_struct _GLFWwin; + +struct _GLFWwin_struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // User callback functions + GLFWwindowsizefun windowSizeCallback; + GLFWwindowclosefun windowCloseCallback; + GLFWwindowrefreshfun windowRefreshCallback; + GLFWmousebuttonfun mouseButtonCallback; + GLFWmouseposfun mousePosCallback; + GLFWmousewheelfun mouseWheelCallback; + GLFWkeyfun keyCallback; + GLFWcharfun charCallback; + + // User selected window settings + int fullscreen; // Fullscreen flag + int mouseLock; // Mouse-lock flag + int autoPollEvents; // Auto polling flag + int sysKeysDisabled; // System keys disabled flag + int windowNoResize; // Resize- and maximize gadgets disabled flag + int refreshRate; // Vertical monitor refresh rate + + // Window status & parameters + int opened; // Flag telling if window is opened or not + int active; // Application active flag + int iconified; // Window iconified flag + int width, height; // Window width and heigth + int accelerated; // GL_TRUE if window is HW accelerated + + // Framebuffer attributes + int redBits; + int greenBits; + int blueBits; + int alphaBits; + int depthBits; + int stencilBits; + int accumRedBits; + int accumGreenBits; + int accumBlueBits; + int accumAlphaBits; + int auxBuffers; + int stereo; + int samples; + + // OpenGL extensions and context attributes + int has_GL_SGIS_generate_mipmap; + int has_GL_ARB_texture_non_power_of_two; + int glMajor, glMinor, glRevision; + int glForward, glDebug, glProfile; + + PFNGLGETSTRINGIPROC GetStringi; + + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Platform specific window resources + HDC DC; // Private GDI device context + HGLRC context; // Permanent rendering context + HWND window; // Window handle + ATOM classAtom; // Window class atom + int modeID; // Mode ID for fullscreen mode + HHOOK keyboardHook; // Keyboard hook handle + DWORD dwStyle; // Window styles used for window creation + DWORD dwExStyle; // --"-- + + // Platform specific extensions (context specific) + WGLSWAPINTERVALEXT_T SwapIntervalEXT; + WGLGETPIXELFORMATATTRIBIVARB_T GetPixelFormatAttribivARB; + WGLGETEXTENSIONSSTRINGEXT_T GetExtensionsStringEXT; + WGLGETEXTENSIONSSTRINGARB_T GetExtensionsStringARB; + PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; + GLboolean has_WGL_EXT_swap_control; + GLboolean has_WGL_ARB_multisample; + GLboolean has_WGL_ARB_pixel_format; + GLboolean has_WGL_ARB_create_context; + + // Various platform specific internal variables + int oldMouseLock; // Old mouse-lock flag (used for remembering + // mouse-lock state when iconifying) + int oldMouseLockValid; + int desiredRefreshRate; // Desired vertical monitor refresh rate + +}; + +GLFWGLOBAL _GLFWwin _glfwWin; + + +//------------------------------------------------------------------------ +// User input status (most of this should go in _GLFWwin) +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Mouse status + int MousePosX, MousePosY; + int WheelPos; + char MouseButton[ GLFW_MOUSE_BUTTON_LAST+1 ]; + + // Keyboard status + char Key[ GLFW_KEY_LAST+1 ]; + int LastChar; + + // User selected settings + int StickyKeys; + int StickyMouseButtons; + int KeyRepeat; + + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Platform specific internal variables + int MouseMoved, OldMouseX, OldMouseY; + +} _glfwInput; + + +//------------------------------------------------------------------------ +// Library global data +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + + // Window opening hints + _GLFWhints hints; + +// ========= PLATFORM SPECIFIC PART ====================================== + + HINSTANCE instance; // Instance of the application + + // Timer data + struct { + int HasPerformanceCounter; + double Resolution; + unsigned int t0_32; + __int64 t0_64; + } Timer; + + // System information + struct { + int winVer; + int hasUnicode; + DWORD foregroundLockTimeout; + } Sys; + +#if !defined(_GLFW_NO_DLOAD_WINMM) || !defined(_GLFW_NO_DLOAD_GDI32) + // Library handles and function pointers + struct { +#ifndef _GLFW_NO_DLOAD_GDI32 + // gdi32.dll + HINSTANCE gdi32; + CHOOSEPIXELFORMAT_T ChoosePixelFormat; + DESCRIBEPIXELFORMAT_T DescribePixelFormat; + GETPIXELFORMAT_T GetPixelFormat; + SETPIXELFORMAT_T SetPixelFormat; + SWAPBUFFERS_T SwapBuffers; +#endif // _GLFW_NO_DLOAD_GDI32 + + // winmm.dll +#ifndef _GLFW_NO_DLOAD_WINMM + HINSTANCE winmm; + JOYGETDEVCAPSA_T joyGetDevCapsA; + JOYGETPOS_T joyGetPos; + JOYGETPOSEX_T joyGetPosEx; + TIMEGETTIME_T timeGetTime; +#endif // _GLFW_NO_DLOAD_WINMM + } Libs; +#endif + +} _glfwLibrary; + + +//======================================================================== +// Various Windows version constants +//======================================================================== + +#define _GLFW_WIN_UNKNOWN 0x0000 // Earlier than 95 or NT4 +#define _GLFW_WIN_95 0x0001 +#define _GLFW_WIN_98 0x0002 +#define _GLFW_WIN_ME 0x0003 +#define _GLFW_WIN_UNKNOWN_9x 0x0004 // Later than ME +#define _GLFW_WIN_NT4 0x0101 +#define _GLFW_WIN_2K 0x0102 +#define _GLFW_WIN_XP 0x0103 +#define _GLFW_WIN_NET_SERVER 0x0104 +#define _GLFW_WIN_UNKNOWN_NT 0x0105 // Later than .NET Server + + +//======================================================================== +// Prototypes for platform specific internal functions +//======================================================================== + +// Time +void _glfwInitTimer( void ); + +// Fullscreen support +int _glfwGetClosestVideoModeBPP( int *w, int *h, int *bpp, int *refresh ); +int _glfwGetClosestVideoMode( int *w, int *h, int *r, int *g, int *b, int *refresh ); +void _glfwSetVideoModeMODE( int mode ); +void _glfwSetVideoMode( int *w, int *h, int r, int g, int b, int refresh ); + + +#endif // _platform_h_ diff --git a/lib/win32/win32_dllmain.c b/lib/win32/win32_dllmain.c new file mode 100644 index 00000000..d7a9c1a9 --- /dev/null +++ b/lib/win32/win32_dllmain.c @@ -0,0 +1,49 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Win32/WGL +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +#if defined(GLFW_BUILD_DLL) + +//======================================================================== +// GLFW DLL entry point +//======================================================================== + +BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, LPVOID reserved ) +{ + // NOTE: Some compilers complains about instance and x never being used - + // never mind that (we don't want to use them)! + + return TRUE; +} + +#endif // GLFW_BUILD_DLL + diff --git a/lib/win32/win32_enable.c b/lib/win32/win32_enable.c new file mode 100644 index 00000000..3e72b787 --- /dev/null +++ b/lib/win32/win32_enable.c @@ -0,0 +1,155 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Win32/WGL +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// Low level keyboard hook (system callback) function +// Used to disable system keys under Windows NT +//======================================================================== + +static LRESULT CALLBACK keyboardHook( int nCode, WPARAM wParam, LPARAM lParam ) +{ + BOOL syskeys = FALSE; + PKBDLLHOOKSTRUCT p; + + // We are only looking for keyboard events - interpret lParam as a + // pointer to a KBDLLHOOKSTRUCT + p = (PKBDLLHOOKSTRUCT) lParam; + + if( nCode == HC_ACTION ) + { + // We have a keyboard event + + switch( wParam ) + { + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: + // Detect: ALT+TAB, ALT+ESC, ALT+F4, CTRL+ESC, + // LWIN, RWIN, APPS (mysterious menu key) + syskeys = ( p->vkCode == VK_TAB && + p->flags & LLKHF_ALTDOWN ) || + ( p->vkCode == VK_ESCAPE && + p->flags & LLKHF_ALTDOWN ) || + ( p->vkCode == VK_F4 && + p->flags & LLKHF_ALTDOWN ) || + ( p->vkCode == VK_ESCAPE && + (GetKeyState(VK_CONTROL) & 0x8000)) || + p->vkCode == VK_LWIN || + p->vkCode == VK_RWIN || + p->vkCode == VK_APPS; + break; + + default: + break; + } + } + + // Was it a system key combination (e.g. ALT+TAB)? + if( syskeys ) + { + // Pass the key event to our window message loop + if( _glfwWin.opened ) + { + PostMessage( _glfwWin.window, (UINT) wParam, p->vkCode, 0 ); + } + + // We've taken care of it - don't let the system know about this + // key event + return 1; + } + else + { + // It's a harmless key press, let the system deal with it + return CallNextHookEx( _glfwWin.keyboardHook, nCode, wParam, lParam ); + } +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Enable system keys +//======================================================================== + +void _glfwPlatformEnableSystemKeys( void ) +{ + BOOL dummy; + + // Use different methods depending on operating system version + if( _glfwLibrary.Sys.winVer >= _GLFW_WIN_NT4 ) + { + if( _glfwWin.keyboardHook != NULL ) + { + UnhookWindowsHookEx( _glfwWin.keyboardHook ); + _glfwWin.keyboardHook = NULL; + } + } + else + { + (void) SystemParametersInfo( SPI_SETSCREENSAVERRUNNING, FALSE, &dummy, 0 ); + } +} + +//======================================================================== +// Disable system keys +//======================================================================== + +void _glfwPlatformDisableSystemKeys( void ) +{ + BOOL dummy; + + // Use different methods depending on operating system version + if( _glfwLibrary.Sys.winVer >= _GLFW_WIN_NT4 ) + { + // Under Windows NT, install a low level keyboard hook + _glfwWin.keyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, + keyboardHook, + _glfwLibrary.instance, + 0 ); + } + else + { + // Under Windows 95/98/ME, fool Windows that a screensaver + // is running => prevents ALT+TAB, CTRL+ESC and CTRL+ALT+DEL + (void) SystemParametersInfo( SPI_SETSCREENSAVERRUNNING, TRUE, &dummy, 0 ); + } +} + diff --git a/lib/win32/win32_fullscreen.c b/lib/win32/win32_fullscreen.c new file mode 100644 index 00000000..5784d797 --- /dev/null +++ b/lib/win32/win32_fullscreen.c @@ -0,0 +1,320 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Win32/WGL +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// Convert BPP to RGB bits based on "best guess" +//======================================================================== + +static void bpp2rgb( int bpp, int *r, int *g, int *b ) +{ + int delta; + + // We assume that by 32 they really meant 24 + if( bpp == 32 ) + { + bpp = 24; + } + + // Convert "bits per pixel" to red, green & blue sizes + + *r = *g = *b = bpp / 3; + delta = bpp - (*r * 3); + if( delta >= 1 ) + { + *g = *g + 1; + } + if( delta == 2 ) + { + *r = *r + 1; + } +} + + +//======================================================================== +// Return closest video mode by dimensions, refresh rate and bits per pixel +//======================================================================== + +int _glfwGetClosestVideoModeBPP( int *w, int *h, int *bpp, int *refresh ) +{ + int mode, bestmode, match, bestmatch, rr, bestrr, success; + DEVMODE dm; + + // Find best match + bestmatch = 0x7fffffff; + bestrr = 0x7fffffff; + mode = bestmode = 0; + do + { + dm.dmSize = sizeof( DEVMODE ); + success = EnumDisplaySettings( NULL, mode, &dm ); + if( success ) + { + match = dm.dmBitsPerPel - *bpp; + if( match < 0 ) match = -match; + match = ( match << 25 ) | + ( (dm.dmPelsWidth - *w) * + (dm.dmPelsWidth - *w) + + (dm.dmPelsHeight - *h) * + (dm.dmPelsHeight - *h) ); + if( match < bestmatch ) + { + bestmatch = match; + bestmode = mode; + bestrr = (dm.dmDisplayFrequency - *refresh) * + (dm.dmDisplayFrequency - *refresh); + } + else if( match == bestmatch && *refresh > 0 ) + { + rr = (dm.dmDisplayFrequency - *refresh) * + (dm.dmDisplayFrequency - *refresh); + if( rr < bestrr ) + { + bestmatch = match; + bestmode = mode; + bestrr = rr; + } + } + } + mode ++; + } + while( success ); + + // Get the parameters for the best matching display mode + dm.dmSize = sizeof( DEVMODE ); + (void) EnumDisplaySettings( NULL, bestmode, &dm ); + + // Fill out actual width and height + *w = dm.dmPelsWidth; + *h = dm.dmPelsHeight; + + // Return bits per pixel + *bpp = dm.dmBitsPerPel; + + // Return vertical refresh rate + *refresh = dm.dmDisplayFrequency; + + return bestmode; +} + + +//======================================================================== +// Return closest video mode by dimensions, refresh rate and channel sizes +//======================================================================== + +static int getClosestVideoMode( int *w, int *h, + int *r, int *g, int *b, + int *refresh ) +{ + int bpp, bestmode; + + // Colorbits = sum of red/green/blue bits + bpp = *r + *g + *b; + + // If colorbits < 15 (e.g. 0) or >= 24, default to 32 bpp + if( bpp < 15 || bpp >= 24 ) + { + bpp = 32; + } + + // Find best match + bestmode = _glfwGetClosestVideoModeBPP( w, h, &bpp, refresh ); + + // Convert "bits per pixel" to red, green & blue sizes + bpp2rgb( bpp, r, g, b ); + + return bestmode; +} + + +//======================================================================== +// Change the current video mode +//======================================================================== + +void _glfwSetVideoModeMODE( int mode ) +{ + DEVMODE dm; + int success; + + // Get the parameters for the best matching display mode + dm.dmSize = sizeof( DEVMODE ); + (void) EnumDisplaySettings( NULL, mode, &dm ); + + // Set which fields we want to specify + dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; + + // Do we have a prefered refresh rate? + if( _glfwWin.desiredRefreshRate > 0 ) + { + dm.dmFields = dm.dmFields | DM_DISPLAYFREQUENCY; + dm.dmDisplayFrequency = _glfwWin.desiredRefreshRate; + } + + // Change display setting + dm.dmSize = sizeof( DEVMODE ); + success = ChangeDisplaySettings( &dm, CDS_FULLSCREEN ); + + // If the mode change was not possible, query the current display + // settings (we'll use the desktop resolution for fullscreen mode) + if( success == DISP_CHANGE_SUCCESSFUL ) + { + _glfwWin.modeID = mode; + } + else + { + _glfwWin.modeID = ENUM_REGISTRY_SETTINGS; + EnumDisplaySettings( NULL, ENUM_REGISTRY_SETTINGS, &dm ); + } + + // Set the window size to that of the display mode + _glfwWin.width = dm.dmPelsWidth; + _glfwWin.height = dm.dmPelsHeight; +} + + +//======================================================================== +// _glfwSetVideoMode() - Change the current video mode +//======================================================================== + +void _glfwSetVideoMode( int *w, int *h, int r, int g, int b, int refresh ) +{ + int bestmode; + + // Find a best match mode + bestmode = getClosestVideoMode( w, h, &r, &g, &b, &refresh ); + + // Change mode + _glfwSetVideoModeMODE( bestmode ); +} + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformGetVideoModes() - Get a list of available video modes +//======================================================================== + +int _glfwPlatformGetVideoModes( GLFWvidmode *list, int maxcount ) +{ + int count, success, mode, i, j; + int m1, m2, bpp, r, g, b; + DEVMODE dm; + + // Loop through all video modes and extract all the UNIQUE modes + count = 0; + mode = 0; + do + { + // Get video mode properties + dm.dmSize = sizeof( DEVMODE ); + success = EnumDisplaySettings( NULL, mode, &dm ); + + // Is it a valid mode? (only list depths >= 15 bpp) + if( success && dm.dmBitsPerPel >= 15 ) + { + // Convert to RGB, and back to bpp ("mask out" alpha bits etc) + bpp2rgb( dm.dmBitsPerPel, &r, &g, &b ); + bpp = r + g + b; + + // Mode "code" for this mode + m1 = (bpp << 25) | (dm.dmPelsWidth * dm.dmPelsHeight); + + // Insert mode in list (sorted), and avoid duplicates + for( i = 0; i < count; i ++ ) + { + // Mode "code" for already listed mode + bpp = list[i].RedBits + list[i].GreenBits + + list[i].BlueBits; + m2 = (bpp << 25) | (list[i].Width * list[i].Height); + if( m1 <= m2 ) + { + break; + } + } + + // New entry at the end of the list? + if( i >= count ) + { + list[count].Width = dm.dmPelsWidth; + list[count].Height = dm.dmPelsHeight; + list[count].RedBits = r; + list[count].GreenBits = g; + list[count].BlueBits = b; + count ++; + } + // Insert new entry in the list? + else if( m1 < m2 ) + { + for( j = count; j > i; j -- ) + { + list[j] = list[j-1]; + } + list[i].Width = dm.dmPelsWidth; + list[i].Height = dm.dmPelsHeight; + list[i].RedBits = r; + list[i].GreenBits = g; + list[i].BlueBits = b; + count ++; + } + } + mode ++; + } + while( success && (count < maxcount) ); + + return count; +} + + +//======================================================================== +// Get the desktop video mode +//======================================================================== + +void _glfwPlatformGetDesktopMode( GLFWvidmode *mode ) +{ + DEVMODE dm; + + // Get desktop display mode + dm.dmSize = sizeof( DEVMODE ); + (void) EnumDisplaySettings( NULL, ENUM_REGISTRY_SETTINGS, &dm ); + + // Return desktop mode parameters + mode->Width = dm.dmPelsWidth; + mode->Height = dm.dmPelsHeight; + bpp2rgb( dm.dmBitsPerPel, &mode->RedBits, &mode->GreenBits, &mode->BlueBits ); +} + diff --git a/lib/win32/win32_glext.c b/lib/win32/win32_glext.c new file mode 100644 index 00000000..820adc50 --- /dev/null +++ b/lib/win32/win32_glext.c @@ -0,0 +1,82 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Win32/WGL +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Check if the current context supports the specified WGL extension +//======================================================================== + +int _glfwPlatformExtensionSupported( const char *extension ) +{ + const GLubyte *extensions; + + if( _glfwWin.GetExtensionsStringEXT != NULL ) + { + extensions = (GLubyte *) _glfwWin.GetExtensionsStringEXT(); + if( extensions != NULL ) + { + if( _glfwStringInExtensionString( extension, extensions ) ) + { + return GL_TRUE; + } + } + } + + if( _glfwWin.GetExtensionsStringARB != NULL ) + { + extensions = (GLubyte *) _glfwWin.GetExtensionsStringARB( _glfwWin.DC ); + if( extensions != NULL ) + { + if( _glfwStringInExtensionString( extension, extensions ) ) + { + return GL_TRUE; + } + } + } + + return GL_FALSE; +} + + +//======================================================================== +// Get the function pointer to an OpenGL function +//======================================================================== + +void *_glfwPlatformGetProcAddress( const char *procname ) +{ + return (void *) wglGetProcAddress( procname ); +} + diff --git a/lib/win32/win32_init.c b/lib/win32/win32_init.c new file mode 100644 index 00000000..8ad41af1 --- /dev/null +++ b/lib/win32/win32_init.c @@ -0,0 +1,281 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Win32/WGL +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +// With the Borland C++ compiler, we want to disable FPU exceptions +#ifdef __BORLANDC__ +#include +#endif // __BORLANDC__ + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwInitLibraries() - Load necessary libraries (DLLs) +//======================================================================== + +static int _glfwInitLibraries( void ) +{ + // gdi32.dll (OpenGL pixel format functions & SwapBuffers) +#ifndef _GLFW_NO_DLOAD_GDI32 + _glfwLibrary.Libs.gdi32 = LoadLibrary( "gdi32.dll" ); + if( _glfwLibrary.Libs.gdi32 != NULL ) + { + _glfwLibrary.Libs.ChoosePixelFormat = (CHOOSEPIXELFORMAT_T) + GetProcAddress( _glfwLibrary.Libs.gdi32, "ChoosePixelFormat" ); + _glfwLibrary.Libs.DescribePixelFormat = (DESCRIBEPIXELFORMAT_T) + GetProcAddress( _glfwLibrary.Libs.gdi32, "DescribePixelFormat" ); + _glfwLibrary.Libs.GetPixelFormat = (GETPIXELFORMAT_T) + GetProcAddress( _glfwLibrary.Libs.gdi32, "GetPixelFormat" ); + _glfwLibrary.Libs.SetPixelFormat = (SETPIXELFORMAT_T) + GetProcAddress( _glfwLibrary.Libs.gdi32, "SetPixelFormat" ); + _glfwLibrary.Libs.SwapBuffers = (SWAPBUFFERS_T) + GetProcAddress( _glfwLibrary.Libs.gdi32, "SwapBuffers" ); + if( _glfwLibrary.Libs.ChoosePixelFormat == NULL || + _glfwLibrary.Libs.DescribePixelFormat == NULL || + _glfwLibrary.Libs.GetPixelFormat == NULL || + _glfwLibrary.Libs.SetPixelFormat == NULL || + _glfwLibrary.Libs.SwapBuffers == NULL ) + { + FreeLibrary( _glfwLibrary.Libs.gdi32 ); + _glfwLibrary.Libs.gdi32 = NULL; + return GL_FALSE; + } + } + else + { + return GL_FALSE; + } +#endif // _GLFW_NO_DLOAD_GDI32 + + // winmm.dll (for joystick and timer support) +#ifndef _GLFW_NO_DLOAD_WINMM + _glfwLibrary.Libs.winmm = LoadLibrary( "winmm.dll" ); + if( _glfwLibrary.Libs.winmm != NULL ) + { + _glfwLibrary.Libs.joyGetDevCapsA = (JOYGETDEVCAPSA_T) + GetProcAddress( _glfwLibrary.Libs.winmm, "joyGetDevCapsA" ); + _glfwLibrary.Libs.joyGetPos = (JOYGETPOS_T) + GetProcAddress( _glfwLibrary.Libs.winmm, "joyGetPos" ); + _glfwLibrary.Libs.joyGetPosEx = (JOYGETPOSEX_T) + GetProcAddress( _glfwLibrary.Libs.winmm, "joyGetPosEx" ); + _glfwLibrary.Libs.timeGetTime = (TIMEGETTIME_T) + GetProcAddress( _glfwLibrary.Libs.winmm, "timeGetTime" ); + if( _glfwLibrary.Libs.joyGetDevCapsA == NULL || + _glfwLibrary.Libs.joyGetPos == NULL || + _glfwLibrary.Libs.joyGetPosEx == NULL || + _glfwLibrary.Libs.timeGetTime == NULL ) + { + FreeLibrary( _glfwLibrary.Libs.winmm ); + _glfwLibrary.Libs.winmm = NULL; + return GL_FALSE; + } + } + else + { + return GL_FALSE; + } +#endif // _GLFW_NO_DLOAD_WINMM + + return GL_TRUE; +} + + +//======================================================================== +// _glfwFreeLibraries() - Unload used libraries (DLLs) +//======================================================================== + +static void _glfwFreeLibraries( void ) +{ + // gdi32.dll +#ifndef _GLFW_NO_DLOAD_GDI32 + if( _glfwLibrary.Libs.gdi32 != NULL ) + { + FreeLibrary( _glfwLibrary.Libs.gdi32 ); + _glfwLibrary.Libs.gdi32 = NULL; + } +#endif // _GLFW_NO_DLOAD_GDI32 + + // winmm.dll +#ifndef _GLFW_NO_DLOAD_WINMM + if( _glfwLibrary.Libs.winmm != NULL ) + { + FreeLibrary( _glfwLibrary.Libs.winmm ); + _glfwLibrary.Libs.winmm = NULL; + } +#endif // _GLFW_NO_DLOAD_WINMM +} + + +//======================================================================== +// _glfwTerminate_atexit() - Terminate GLFW when exiting application +//======================================================================== + +void _glfwTerminate_atexit( void ) +{ + glfwTerminate(); +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformInit() - Initialize various GLFW state +//======================================================================== + +int _glfwPlatformInit( void ) +{ + OSVERSIONINFO osi; + + // To make SetForegroundWindow() work as we want, we need to fiddle + // with the FOREGROUNDLOCKTIMEOUT system setting (we do this as early + // as possible in the hope of still being the foreground process) + SystemParametersInfo( SPI_GETFOREGROUNDLOCKTIMEOUT, 0, + &_glfwLibrary.Sys.foregroundLockTimeout, 0 ); + SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, + SPIF_SENDCHANGE ); + + // Check which OS version we are running + osi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); + GetVersionEx( &osi ); + _glfwLibrary.Sys.winVer = _GLFW_WIN_UNKNOWN; + if( osi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) + { + if( osi.dwMajorVersion == 4 && osi.dwMinorVersion < 10 ) + { + _glfwLibrary.Sys.winVer = _GLFW_WIN_95; + } + else if( osi.dwMajorVersion == 4 && osi.dwMinorVersion < 90 ) + { + _glfwLibrary.Sys.winVer = _GLFW_WIN_98; + } + else if( osi.dwMajorVersion == 4 && osi.dwMinorVersion == 90 ) + { + _glfwLibrary.Sys.winVer = _GLFW_WIN_ME; + } + else if( osi.dwMajorVersion >= 4 ) + { + _glfwLibrary.Sys.winVer = _GLFW_WIN_UNKNOWN_9x; + } + } + else if( osi.dwPlatformId == VER_PLATFORM_WIN32_NT ) + { + if( osi.dwMajorVersion == 4 && osi.dwMinorVersion == 0 ) + { + _glfwLibrary.Sys.winVer = _GLFW_WIN_NT4; + } + else if( osi.dwMajorVersion == 5 && osi.dwMinorVersion == 0 ) + { + _glfwLibrary.Sys.winVer = _GLFW_WIN_2K; + } + else if( osi.dwMajorVersion == 5 && osi.dwMinorVersion == 1 ) + { + _glfwLibrary.Sys.winVer = _GLFW_WIN_XP; + } + else if( osi.dwMajorVersion == 5 && osi.dwMinorVersion == 2 ) + { + _glfwLibrary.Sys.winVer = _GLFW_WIN_NET_SERVER; + } + else if( osi.dwMajorVersion >= 5 ) + { + _glfwLibrary.Sys.winVer = _GLFW_WIN_UNKNOWN_NT; + } + } + + // Do we have Unicode support? + if( _glfwLibrary.Sys.winVer >= _GLFW_WIN_NT4 ) + { + // Windows NT/2000/XP/.NET has Unicode support + _glfwLibrary.Sys.hasUnicode = GL_TRUE; + } + else + { + // Windows 9x/ME does not have Unicode support + _glfwLibrary.Sys.hasUnicode = GL_FALSE; + } + + // Load libraries (DLLs) + if( !_glfwInitLibraries() ) + { + return GL_FALSE; + } + + // With the Borland C++ compiler, we want to disable FPU exceptions + // (this is recommended for OpenGL applications under Windows) +#ifdef __BORLANDC__ + _control87( MCW_EM, MCW_EM ); +#endif + + // Retrieve GLFW instance handle + _glfwLibrary.instance = GetModuleHandle( NULL ); + + // System keys are not disabled + _glfwWin.keyboardHook = NULL; + + // Install atexit() routine + atexit( _glfwTerminate_atexit ); + + // Start the timer + _glfwInitTimer(); + + return GL_TRUE; +} + + +//======================================================================== +// Close window and shut down library +//======================================================================== + +int _glfwPlatformTerminate( void ) +{ + // Close OpenGL window + glfwCloseWindow(); + + // Enable system keys again (if they were disabled) + glfwEnable( GLFW_SYSTEM_KEYS ); + + // Unload libraries (DLLs) + _glfwFreeLibraries(); + + // Restore FOREGROUNDLOCKTIMEOUT system setting + SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT, 0, + (LPVOID)_glfwLibrary.Sys.foregroundLockTimeout, + SPIF_SENDCHANGE ); + + return GL_TRUE; +} + diff --git a/lib/win32/win32_joystick.c b/lib/win32/win32_joystick.c new file mode 100644 index 00000000..64b55899 --- /dev/null +++ b/lib/win32/win32_joystick.c @@ -0,0 +1,234 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Win32/WGL +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwJoystickPresent() - Return GL_TRUE if joystick is present, +// else return GL_FALSE. +//======================================================================== + +static int _glfwJoystickPresent( int joy ) +{ + JOYINFO ji; + + // Windows NT 4.0 MMSYSTEM only supports 2 sticks (other Windows + // versions support 16 sticks) + if( _glfwLibrary.Sys.winVer == _GLFW_WIN_NT4 && joy > GLFW_JOYSTICK_2 ) + { + return GL_FALSE; + } + + // Is it a valid stick ID (Windows don't support more than 16 sticks)? + if( joy < GLFW_JOYSTICK_1 || joy > GLFW_JOYSTICK_16 ) + { + return GL_FALSE; + } + + // Is the joystick present? + if( _glfw_joyGetPos( joy - GLFW_JOYSTICK_1, &ji ) != JOYERR_NOERROR ) + { + return GL_FALSE; + } + + return GL_TRUE; +} + + +//======================================================================== +// _glfwCalcJoystickPos() - Calculate joystick position +//======================================================================== + +static float _glfwCalcJoystickPos( DWORD pos, DWORD min, DWORD max ) +{ + float fpos = (float) pos; + float fmin = (float) min; + float fmax = (float) max; + return (2.0f*(fpos - fmin) / (fmax - fmin)) - 1.0f; +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformGetJoystickParam() - Determine joystick capabilities +//======================================================================== + +int _glfwPlatformGetJoystickParam( int joy, int param ) +{ + JOYCAPS jc; + +// return 0; + + // Is joystick present? + if( !_glfwJoystickPresent( joy ) ) + { + return 0; + } + + // We got this far, the joystick is present + if( param == GLFW_PRESENT ) + { + return GL_TRUE; + } + + // Get joystick capabilities + _glfw_joyGetDevCaps( joy - GLFW_JOYSTICK_1, &jc, sizeof(JOYCAPS) ); + + switch( param ) + { + case GLFW_AXES: + // Return number of joystick axes + return jc.wNumAxes; + + case GLFW_BUTTONS: + // Return number of joystick axes + return jc.wNumButtons; + + default: + break; + } + + return 0; +} + + +//======================================================================== +// _glfwPlatformGetJoystickPos() - Get joystick axis positions +//======================================================================== + +int _glfwPlatformGetJoystickPos( int joy, float *pos, int numaxes ) +{ + JOYCAPS jc; + JOYINFOEX ji; + int axis; + +// return 0; + + // Is joystick present? + if( !_glfwJoystickPresent( joy ) ) + { + return 0; + } + + // Get joystick capabilities + _glfw_joyGetDevCaps( joy - GLFW_JOYSTICK_1, &jc, sizeof(JOYCAPS) ); + + // Get joystick state + ji.dwSize = sizeof( JOYINFOEX ); + ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | + JOY_RETURNR | JOY_RETURNU | JOY_RETURNV; + _glfw_joyGetPosEx( joy - GLFW_JOYSTICK_1, &ji ); + + // Get position values for all axes + axis = 0; + if( axis < numaxes ) + { + pos[ axis++ ] = _glfwCalcJoystickPos( ji.dwXpos, jc.wXmin, + jc.wXmax ); + } + if( axis < numaxes ) + { + pos[ axis++ ] = -_glfwCalcJoystickPos( ji.dwYpos, jc.wYmin, + jc.wYmax ); + } + if( axis < numaxes && jc.wCaps & JOYCAPS_HASZ ) + { + pos[ axis++ ] = _glfwCalcJoystickPos( ji.dwZpos, jc.wZmin, + jc.wZmax ); + } + if( axis < numaxes && jc.wCaps & JOYCAPS_HASR ) + { + pos[ axis++ ] = _glfwCalcJoystickPos( ji.dwRpos, jc.wRmin, + jc.wRmax ); + } + if( axis < numaxes && jc.wCaps & JOYCAPS_HASU ) + { + pos[ axis++ ] = _glfwCalcJoystickPos( ji.dwUpos, jc.wUmin, + jc.wUmax ); + } + if( axis < numaxes && jc.wCaps & JOYCAPS_HASV ) + { + pos[ axis++ ] = -_glfwCalcJoystickPos( ji.dwVpos, jc.wVmin, + jc.wVmax ); + } + + // Return number of returned axes + return axis; +} + + +//======================================================================== +// _glfwPlatformGetJoystickButtons() - Get joystick button states +//======================================================================== + +int _glfwPlatformGetJoystickButtons( int joy, unsigned char *buttons, + int numbuttons ) +{ + JOYCAPS jc; + JOYINFOEX ji; + int button; + +// return 0; + + // Is joystick present? + if( !_glfwJoystickPresent( joy ) ) + { + return 0; + } + + // Get joystick capabilities + _glfw_joyGetDevCaps( joy - GLFW_JOYSTICK_1, &jc, sizeof(JOYCAPS) ); + + // Get joystick state + ji.dwSize = sizeof( JOYINFOEX ); + ji.dwFlags = JOY_RETURNBUTTONS; + _glfw_joyGetPosEx( joy - GLFW_JOYSTICK_1, &ji ); + + // Get states of all requested buttons + button = 0; + while( button < numbuttons && button < (int) jc.wNumButtons ) + { + buttons[ button ] = (unsigned char) + (ji.dwButtons & (1UL << button) ? GLFW_PRESS : GLFW_RELEASE); + button ++; + } + + return button; +} + diff --git a/lib/win32/win32_time.c b/lib/win32/win32_time.c new file mode 100644 index 00000000..6bd112c3 --- /dev/null +++ b/lib/win32/win32_time.c @@ -0,0 +1,118 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Win32/WGL +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwInitTimer() - Initialise timer +//======================================================================== + +void _glfwInitTimer( void ) +{ + __int64 freq; + + // Check if we have a performance counter + if( QueryPerformanceFrequency( (LARGE_INTEGER *)&freq ) ) + { + // Performance counter is available => use it! + _glfwLibrary.Timer.HasPerformanceCounter = GL_TRUE; + + // Counter resolution is 1 / counter frequency + _glfwLibrary.Timer.Resolution = 1.0 / (double)freq; + + // Set start time for timer + QueryPerformanceCounter( (LARGE_INTEGER *)&_glfwLibrary.Timer.t0_64 ); + } + else + { + // No performace counter available => use the tick counter + _glfwLibrary.Timer.HasPerformanceCounter = GL_FALSE; + + // Counter resolution is 1 ms + _glfwLibrary.Timer.Resolution = 0.001; + + // Set start time for timer + _glfwLibrary.Timer.t0_32 = _glfw_timeGetTime(); + } +} + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Return timer value in seconds +//======================================================================== + +double _glfwPlatformGetTime( void ) +{ + double t; + __int64 t_64; + + if( _glfwLibrary.Timer.HasPerformanceCounter ) + { + QueryPerformanceCounter( (LARGE_INTEGER *)&t_64 ); + t = (double)(t_64 - _glfwLibrary.Timer.t0_64); + } + else + { + t = (double)(_glfw_timeGetTime() - _glfwLibrary.Timer.t0_32); + } + + // Calculate the current time in seconds + return t * _glfwLibrary.Timer.Resolution; +} + + +//======================================================================== +// Set timer value in seconds +//======================================================================== + +void _glfwPlatformSetTime( double t ) +{ + __int64 t_64; + + if( _glfwLibrary.Timer.HasPerformanceCounter ) + { + QueryPerformanceCounter( (LARGE_INTEGER *)&t_64 ); + _glfwLibrary.Timer.t0_64 = t_64 - (__int64)(t/_glfwLibrary.Timer.Resolution); + } + else + { + _glfwLibrary.Timer.t0_32 = _glfw_timeGetTime() - (int)(t*1000.0); + } +} + diff --git a/lib/win32/win32_window.c b/lib/win32/win32_window.c new file mode 100644 index 00000000..15071c36 --- /dev/null +++ b/lib/win32/win32_window.c @@ -0,0 +1,1817 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Win32/WGL +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +// We use versioned window class names in order not to cause conflicts +// between applications using different versions of GLFW +#define _GLFW_WNDCLASSNAME "GLFW27" + + +//======================================================================== +// Enable/disable minimize/restore animations +//======================================================================== + +static int setMinMaxAnimations( int enable ) +{ + ANIMATIONINFO AI; + int old_enable; + + // Get old animation setting + AI.cbSize = sizeof( ANIMATIONINFO ); + SystemParametersInfo( SPI_GETANIMATION, AI.cbSize, &AI, 0 ); + old_enable = AI.iMinAnimate; + + // If requested, change setting + if( old_enable != enable ) + { + AI.iMinAnimate = enable; + SystemParametersInfo( SPI_SETANIMATION, AI.cbSize, &AI, + SPIF_SENDCHANGE ); + } + + return old_enable; +} + + +//======================================================================== +// Focus the window and bring it to the top of the stack +// Due to some nastiness with how Win98/ME/2k/XP handles SetForegroundWindow, +// we have to go through some really bizarre measures to achieve this +//======================================================================== + +static void setForegroundWindow( HWND hWnd ) +{ + int try_count = 0; + int old_animate; + + // Try the standard approach first... + BringWindowToTop( hWnd ); + SetForegroundWindow( hWnd ); + + // If it worked, return now + if( hWnd == GetForegroundWindow() ) + { + // Try to modify the system settings (since this is the foreground + // process, we are allowed to do this) + SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, + SPIF_SENDCHANGE ); + return; + } + + // For other Windows versions than 95 & NT4.0, the standard approach + // may not work, so if we failed we have to "trick" Windows into + // making our window the foureground window: Iconify and restore + // again. It is ugly, but it seems to work (we turn off those annoying + // zoom animations to make it look a bit better at least). + + // Turn off minimize/restore animations + old_animate = setMinMaxAnimations( 0 ); + + // We try this a few times, just to be on the safe side of things... + do + { + // Iconify & restore + ShowWindow( hWnd, SW_HIDE ); + ShowWindow( hWnd, SW_SHOWMINIMIZED ); + ShowWindow( hWnd, SW_SHOWNORMAL ); + + // Try to get focus + BringWindowToTop( hWnd ); + SetForegroundWindow( hWnd ); + + // We do not want to keep going on forever, so we keep track of + // how many times we tried + try_count ++; + } + while( hWnd != GetForegroundWindow() && try_count <= 3 ); + + // Restore the system minimize/restore animation setting + (void) setMinMaxAnimations( old_animate ); + + // Try to modify the system settings (since this is now hopefully the + // foreground process, we are probably allowed to do this) + SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, + SPIF_SENDCHANGE ); +} + + +//======================================================================== +// Returns the specified attribute of the specified pixel format +// NOTE: Do not call this unless we have found WGL_ARB_pixel_format +//======================================================================== + +static int getPixelFormatAttrib(int pixelFormat, int attrib) +{ + int value = 0; + + if( !_glfwWin.GetPixelFormatAttribivARB( _glfwWin.DC, pixelFormat, 0, 1, &attrib, &value) ) + { + // NOTE: We should probably handle this error somehow + return 0; + } + + return value; +} + + +//======================================================================== +// Return a list of available and usable framebuffer configs +//======================================================================== + +static _GLFWfbconfig *getFBConfigs( unsigned int *found ) +{ + _GLFWfbconfig *result; + PIXELFORMATDESCRIPTOR pfd; + int i, count; + + *found = 0; + + if( _glfwWin.has_WGL_ARB_pixel_format ) + { + count = getPixelFormatAttrib( 1, WGL_NUMBER_PIXEL_FORMATS_ARB ); + } + else + { + count = _glfw_DescribePixelFormat( _glfwWin.DC, 1, sizeof( PIXELFORMATDESCRIPTOR ), NULL ); + } + + if( !count ) + { + fprintf( stderr, "No Win32 pixel formats available\n" ); + return NULL; + } + + result = (_GLFWfbconfig*) malloc( sizeof( _GLFWfbconfig ) * count ); + if( !result ) + { + fprintf(stderr, "Out of memory"); + return NULL; + } + + for( i = 1; i <= count; i++ ) + { + if( _glfwWin.has_WGL_ARB_pixel_format ) + { + // Get pixel format attributes through WGL_ARB_pixel_format + + if( !getPixelFormatAttrib( i, WGL_SUPPORT_OPENGL_ARB ) || + !getPixelFormatAttrib( i, WGL_DRAW_TO_WINDOW_ARB ) || + !getPixelFormatAttrib( i, WGL_DOUBLE_BUFFER_ARB ) ) + { + // Only consider doublebuffered OpenGL pixel formats for windows + continue; + } + + if( getPixelFormatAttrib( i, WGL_PIXEL_TYPE_ARB ) != WGL_TYPE_RGBA_ARB ) + { + // Only consider RGBA pixel formats + continue; + } + + result[*found].redBits = getPixelFormatAttrib( i, WGL_RED_BITS_ARB ); + result[*found].greenBits = getPixelFormatAttrib( i, WGL_GREEN_BITS_ARB ); + result[*found].blueBits = getPixelFormatAttrib( i, WGL_BLUE_BITS_ARB ); + result[*found].alphaBits = getPixelFormatAttrib( i, WGL_ALPHA_BITS_ARB ); + + result[*found].depthBits = getPixelFormatAttrib( i, WGL_DEPTH_BITS_ARB ); + result[*found].stencilBits = getPixelFormatAttrib( i, WGL_STENCIL_BITS_ARB ); + + result[*found].accumRedBits = getPixelFormatAttrib( i, WGL_ACCUM_RED_BITS_ARB ); + result[*found].accumGreenBits = getPixelFormatAttrib( i, WGL_ACCUM_GREEN_BITS_ARB ); + result[*found].accumBlueBits = getPixelFormatAttrib( i, WGL_ACCUM_BLUE_BITS_ARB ); + result[*found].accumAlphaBits = getPixelFormatAttrib( i, WGL_ACCUM_ALPHA_BITS_ARB ); + + result[*found].auxBuffers = getPixelFormatAttrib( i, WGL_AUX_BUFFERS_ARB ); + result[*found].stereo = getPixelFormatAttrib( i, WGL_STEREO_ARB ); + + if( _glfwWin.has_WGL_ARB_multisample ) + { + result[*found].samples = getPixelFormatAttrib( i, WGL_SAMPLES_ARB ); + } + else + { + result[*found].samples = 0; + } + } + else + { + // Get pixel format attributes through old-fashioned PFDs + + if( !_glfw_DescribePixelFormat( _glfwWin.DC, i, sizeof( PIXELFORMATDESCRIPTOR ), &pfd ) ) + { + continue; + } + + if( !( pfd.dwFlags & PFD_DRAW_TO_WINDOW ) || + !( pfd.dwFlags & PFD_SUPPORT_OPENGL ) || + !( pfd.dwFlags & PFD_DOUBLEBUFFER ) ) + { + // Only consider doublebuffered OpenGL pixel formats for windows + continue; + } + + if( !( pfd.dwFlags & PFD_GENERIC_ACCELERATED ) && + ( pfd.dwFlags & PFD_GENERIC_FORMAT ) ) + { + continue; + } + + if( pfd.iPixelType != PFD_TYPE_RGBA ) + { + // Only RGBA pixel formats considered + continue; + } + + result[*found].redBits = pfd.cRedBits; + result[*found].greenBits = pfd.cGreenBits; + result[*found].blueBits = pfd.cBlueBits; + result[*found].alphaBits = pfd.cAlphaBits; + + result[*found].depthBits = pfd.cDepthBits; + result[*found].stencilBits = pfd.cStencilBits; + + result[*found].accumRedBits = pfd.cAccumRedBits; + result[*found].accumGreenBits = pfd.cAccumGreenBits; + result[*found].accumBlueBits = pfd.cAccumBlueBits; + result[*found].accumAlphaBits = pfd.cAccumAlphaBits; + + result[*found].auxBuffers = pfd.cAuxBuffers; + result[*found].stereo = ( pfd.dwFlags & PFD_STEREO ) ? GL_TRUE : GL_FALSE; + + // PFD pixel formats do not support FSAA + result[*found].samples = 0; + } + + result[*found].platformID = i; + + (*found)++; + } + + return result; +} + + +//======================================================================== +// Creates an OpenGL context on the specified device context +//======================================================================== + +static HGLRC createContext( HDC dc, const _GLFWwndconfig* wndconfig, int pixelFormat ) +{ + PIXELFORMATDESCRIPTOR pfd; + int flags, i = 0, attribs[7]; + + if( !_glfw_DescribePixelFormat( dc, pixelFormat, sizeof(pfd), &pfd ) ) + { + return NULL; + } + + if( !_glfw_SetPixelFormat( dc, pixelFormat, &pfd ) ) + { + return NULL; + } + + if( _glfwWin.has_WGL_ARB_create_context ) + { + // Use the newer wglCreateContextAttribsARB + + if( wndconfig->glMajor != 1 || wndconfig->glMinor != 0 ) + { + // Request an explicitly versioned context + + attribs[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB; + attribs[i++] = wndconfig->glMajor; + attribs[i++] = WGL_CONTEXT_MINOR_VERSION_ARB; + attribs[i++] = wndconfig->glMinor; + } + + if( wndconfig->glForward || wndconfig->glDebug ) + { + flags = 0; + + if( wndconfig->glForward ) + { + flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + } + + if( wndconfig->glDebug ) + { + flags |= WGL_CONTEXT_DEBUG_BIT_ARB; + } + + attribs[i++] = WGL_CONTEXT_FLAGS_ARB; + attribs[i++] = flags; + } + + if( wndconfig->glProfile ) + { + if( wndconfig->glProfile == GLFW_OPENGL_CORE_PROFILE ) + { + flags = WGL_CONTEXT_CORE_PROFILE_BIT_ARB; + } + else + { + flags = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + } + + attribs[i++] = WGL_CONTEXT_PROFILE_MASK_ARB; + attribs[i++] = flags; + } + + attribs[i++] = 0; + + return _glfwWin.CreateContextAttribsARB( dc, NULL, attribs ); + } + + return wglCreateContext( dc ); +} + + +//======================================================================== +// Translates a Windows key to the corresponding GLFW key +//======================================================================== + +static int translateKey( WPARAM wParam, LPARAM lParam ) +{ + MSG next_msg; + DWORD msg_time; + DWORD scan_code; + + // Check for numeric keypad keys + // Note: This way we always force "NumLock = ON", which at least + // enables GLFW users to detect numeric keypad keys + int hiFlags = HIWORD( lParam ); + + if ( !( hiFlags & 0x100 ) ) + { + switch( MapVirtualKey( hiFlags & 0xFF, 1 ) ) + { + case VK_INSERT: return GLFW_KEY_KP_0; + case VK_END: return GLFW_KEY_KP_1; + case VK_DOWN: return GLFW_KEY_KP_2; + case VK_NEXT: return GLFW_KEY_KP_3; + case VK_LEFT: return GLFW_KEY_KP_4; + case VK_CLEAR: return GLFW_KEY_KP_5; + case VK_RIGHT: return GLFW_KEY_KP_6; + case VK_HOME: return GLFW_KEY_KP_7; + case VK_UP: return GLFW_KEY_KP_8; + case VK_PRIOR: return GLFW_KEY_KP_9; + case VK_DIVIDE: return GLFW_KEY_KP_DIVIDE; + case VK_MULTIPLY: return GLFW_KEY_KP_MULTIPLY; + case VK_SUBTRACT: return GLFW_KEY_KP_SUBTRACT; + case VK_ADD: return GLFW_KEY_KP_ADD; + case VK_DELETE: return GLFW_KEY_KP_DECIMAL; + } + } + + // Check which key was pressed or released + switch( wParam ) + { + // The SHIFT keys require special handling + case VK_SHIFT: + { + // Compare scan code for this key with that of VK_RSHIFT in + // order to determine which shift key was pressed (left or + // right) + scan_code = MapVirtualKey( VK_RSHIFT, 0 ); + if( ((lParam & 0x01ff0000) >> 16) == scan_code ) + { + return GLFW_KEY_RSHIFT; + } + + return GLFW_KEY_LSHIFT; + } + + // The CTRL keys require special handling + case VK_CONTROL: + { + // Is this an extended key (i.e. right key)? + if( lParam & 0x01000000 ) + { + return GLFW_KEY_RCTRL; + } + + // Here is a trick: "Alt Gr" sends LCTRL, then RALT. We only + // want the RALT message, so we try to see if the next message + // is a RALT message. In that case, this is a false LCTRL! + msg_time = GetMessageTime(); + if( PeekMessage( &next_msg, NULL, 0, 0, PM_NOREMOVE ) ) + { + if( next_msg.message == WM_KEYDOWN || + next_msg.message == WM_SYSKEYDOWN ) + { + if( next_msg.wParam == VK_MENU && + (next_msg.lParam & 0x01000000) && + next_msg.time == msg_time ) + { + // Next message is a RALT down message, which + // means that this is NOT a proper LCTRL message! + return GLFW_KEY_UNKNOWN; + } + } + } + + return GLFW_KEY_LCTRL; + } + + // The ALT keys require special handling + case VK_MENU: + { + // Is this an extended key (i.e. right key)? + if( lParam & 0x01000000 ) + { + return GLFW_KEY_RALT; + } + + return GLFW_KEY_LALT; + } + + // The ENTER keys require special handling + case VK_RETURN: + { + // Is this an extended key (i.e. right key)? + if( lParam & 0x01000000 ) + { + return GLFW_KEY_KP_ENTER; + } + + return GLFW_KEY_ENTER; + } + + // Special keys (non character keys) + case VK_ESCAPE: return GLFW_KEY_ESC; + case VK_TAB: return GLFW_KEY_TAB; + case VK_BACK: return GLFW_KEY_BACKSPACE; + case VK_HOME: return GLFW_KEY_HOME; + case VK_END: return GLFW_KEY_END; + case VK_PRIOR: return GLFW_KEY_PAGEUP; + case VK_NEXT: return GLFW_KEY_PAGEDOWN; + case VK_INSERT: return GLFW_KEY_INSERT; + case VK_DELETE: return GLFW_KEY_DEL; + case VK_LEFT: return GLFW_KEY_LEFT; + case VK_UP: return GLFW_KEY_UP; + case VK_RIGHT: return GLFW_KEY_RIGHT; + case VK_DOWN: return GLFW_KEY_DOWN; + case VK_F1: return GLFW_KEY_F1; + case VK_F2: return GLFW_KEY_F2; + case VK_F3: return GLFW_KEY_F3; + case VK_F4: return GLFW_KEY_F4; + case VK_F5: return GLFW_KEY_F5; + case VK_F6: return GLFW_KEY_F6; + case VK_F7: return GLFW_KEY_F7; + case VK_F8: return GLFW_KEY_F8; + case VK_F9: return GLFW_KEY_F9; + case VK_F10: return GLFW_KEY_F10; + case VK_F11: return GLFW_KEY_F11; + case VK_F12: return GLFW_KEY_F12; + case VK_F13: return GLFW_KEY_F13; + case VK_F14: return GLFW_KEY_F14; + case VK_F15: return GLFW_KEY_F15; + case VK_F16: return GLFW_KEY_F16; + case VK_F17: return GLFW_KEY_F17; + case VK_F18: return GLFW_KEY_F18; + case VK_F19: return GLFW_KEY_F19; + case VK_F20: return GLFW_KEY_F20; + case VK_F21: return GLFW_KEY_F21; + case VK_F22: return GLFW_KEY_F22; + case VK_F23: return GLFW_KEY_F23; + case VK_F24: return GLFW_KEY_F24; + case VK_SPACE: return GLFW_KEY_SPACE; + + // Numeric keypad + case VK_NUMPAD0: return GLFW_KEY_KP_0; + case VK_NUMPAD1: return GLFW_KEY_KP_1; + case VK_NUMPAD2: return GLFW_KEY_KP_2; + case VK_NUMPAD3: return GLFW_KEY_KP_3; + case VK_NUMPAD4: return GLFW_KEY_KP_4; + case VK_NUMPAD5: return GLFW_KEY_KP_5; + case VK_NUMPAD6: return GLFW_KEY_KP_6; + case VK_NUMPAD7: return GLFW_KEY_KP_7; + case VK_NUMPAD8: return GLFW_KEY_KP_8; + case VK_NUMPAD9: return GLFW_KEY_KP_9; + case VK_DIVIDE: return GLFW_KEY_KP_DIVIDE; + case VK_MULTIPLY: return GLFW_KEY_KP_MULTIPLY; + case VK_SUBTRACT: return GLFW_KEY_KP_SUBTRACT; + case VK_ADD: return GLFW_KEY_KP_ADD; + case VK_DECIMAL: return GLFW_KEY_KP_DECIMAL; + case VK_NUMLOCK: return GLFW_KEY_KP_NUM_LOCK; + + case VK_CAPITAL: return GLFW_KEY_CAPS_LOCK; + case VK_SCROLL: return GLFW_KEY_SCROLL_LOCK; + case VK_PAUSE: return GLFW_KEY_PAUSE; + + case VK_LWIN: return GLFW_KEY_LSUPER; + case VK_RWIN: return GLFW_KEY_RSUPER; + case VK_APPS: return GLFW_KEY_MENU; + + // The rest (should be printable keys) + default: + { + // Convert to printable character (ISO-8859-1 or Unicode) + wParam = MapVirtualKey( (UINT) wParam, 2 ) & 0x0000FFFF; + + // Make sure that the character is uppercase + if( _glfwLibrary.Sys.hasUnicode ) + { + wParam = (WPARAM) CharUpperW( (LPWSTR) wParam ); + } + else + { + wParam = (WPARAM) CharUpperA( (LPSTR) wParam ); + } + + // Valid ISO-8859-1 character? + if( (wParam >= 32 && wParam <= 126) || + (wParam >= 160 && wParam <= 255) ) + { + return (int) wParam; + } + + return GLFW_KEY_UNKNOWN; + } + } +} + + +//======================================================================== +// Translates a Windows key to Unicode +//======================================================================== + +static void translateChar( DWORD wParam, DWORD lParam, int action ) +{ + BYTE keyboard_state[ 256 ]; + UCHAR char_buf[ 10 ]; + WCHAR unicode_buf[ 10 ]; + UINT scan_code; + int i, num_chars, unicode; + + GetKeyboardState( keyboard_state ); + + // Derive scan code from lParam and action + scan_code = (lParam & 0x01ff0000) >> 16; + if( action == GLFW_RELEASE ) + { + scan_code |= 0x8000000; + } + + if( _glfwLibrary.Sys.hasUnicode ) + { + num_chars = ToUnicode( + wParam, // virtual-key code + scan_code, // scan code + keyboard_state, // key-state array + unicode_buf, // buffer for translated key + 10, // size of translated key buffer + 0 // active-menu flag + ); + unicode = 1; + } + else + { + // Convert to ISO-8859-1 + num_chars = ToAscii( + wParam, // virtual-key code + scan_code, // scan code + keyboard_state, // key-state array + (LPWORD) char_buf, // buffer for translated key + 0 // active-menu flag + ); + unicode = 0; + } + + // Report characters + for( i = 0; i < num_chars; i++ ) + { + // Get next character from buffer + if( unicode ) + { + _glfwInputChar( (int) unicode_buf[ i ], action ); + } + else + { + _glfwInputChar( (int) char_buf[ i ], action ); + } + } +} + + +//======================================================================== +// Window callback function (handles window events) +//======================================================================== + +static LRESULT CALLBACK windowProc( HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam ) +{ + int wheelDelta, iconified; + + switch( uMsg ) + { + // Window activate message? (iconification?) + case WM_ACTIVATE: + { + _glfwWin.active = LOWORD(wParam) != WA_INACTIVE ? GL_TRUE : GL_FALSE; + + iconified = HIWORD(wParam) ? GL_TRUE : GL_FALSE; + + // Were we deactivated/iconified? + if( (!_glfwWin.active || iconified) && !_glfwWin.iconified ) + { + _glfwInputDeactivation(); + + // If we are in fullscreen mode we need to iconify + if( _glfwWin.opened && _glfwWin.fullscreen ) + { + // Do we need to manually iconify? + if( !iconified ) + { + // Minimize window + CloseWindow( _glfwWin.window ); + iconified = GL_TRUE; + } + + // Restore the original desktop resolution + ChangeDisplaySettings( NULL, CDS_FULLSCREEN ); + } + + // Unlock mouse if locked + if( !_glfwWin.oldMouseLockValid ) + { + _glfwWin.oldMouseLock = _glfwWin.mouseLock; + _glfwWin.oldMouseLockValid = GL_TRUE; + glfwEnable( GLFW_MOUSE_CURSOR ); + } + } + else if( _glfwWin.active || !iconified ) + { + // If we are in fullscreen mode we need to maximize + if( _glfwWin.opened && _glfwWin.fullscreen && _glfwWin.iconified ) + { + // Change display settings to the user selected mode + _glfwSetVideoModeMODE( _glfwWin.modeID ); + + // Do we need to manually restore window? + if( iconified ) + { + // Restore window + OpenIcon( _glfwWin.window ); + iconified = GL_FALSE; + + // Activate window + ShowWindow( hWnd, SW_SHOW ); + setForegroundWindow( _glfwWin.window ); + SetFocus( _glfwWin.window ); + } + } + + // Lock mouse, if necessary + if( _glfwWin.oldMouseLockValid && _glfwWin.oldMouseLock ) + { + glfwDisable( GLFW_MOUSE_CURSOR ); + } + _glfwWin.oldMouseLockValid = GL_FALSE; + } + + _glfwWin.iconified = iconified; + return 0; + } + + case WM_SYSCOMMAND: + { + switch( wParam & 0xfff0 ) + { + case SC_SCREENSAVE: + case SC_MONITORPOWER: + { + if( _glfwWin.fullscreen ) + { + // Disallow screen saver and screen blanking if we are + // running in fullscreen mode + return 0; + } + else + { + break; + } + } + + // User trying to access application menu using ALT? + case SC_KEYMENU: + return 0; + } + break; + } + + case WM_CLOSE: + { + // Translate this to WM_QUIT so that we can handle all cases in the + // same place + PostQuitMessage( 0 ); + return 0; + } + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + { + _glfwInputKey( translateKey( wParam, lParam ), GLFW_PRESS ); + + if( _glfwWin.charCallback ) + { + translateChar( (DWORD) wParam, (DWORD) lParam, GLFW_PRESS ); + } + return 0; + } + + case WM_KEYUP: + case WM_SYSKEYUP: + { + // Special trick: release both shift keys on SHIFT up event + if( wParam == VK_SHIFT ) + { + _glfwInputKey( GLFW_KEY_LSHIFT, GLFW_RELEASE ); + _glfwInputKey( GLFW_KEY_RSHIFT, GLFW_RELEASE ); + } + else + { + _glfwInputKey( translateKey( wParam, lParam ), GLFW_RELEASE ); + } + + if( _glfwWin.charCallback ) + { + translateChar( (DWORD) wParam, (DWORD) lParam, GLFW_RELEASE ); + } + + return 0; + } + + case WM_LBUTTONDOWN: + SetCapture(hWnd); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS ); + return 0; + case WM_RBUTTONDOWN: + SetCapture(hWnd); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS ); + return 0; + case WM_MBUTTONDOWN: + SetCapture(hWnd); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS ); + return 0; + case WM_XBUTTONDOWN: + { + if( HIWORD(wParam) == XBUTTON1 ) + { + SetCapture(hWnd); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_4, GLFW_PRESS ); + } + else if( HIWORD(wParam) == XBUTTON2 ) + { + SetCapture(hWnd); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_5, GLFW_PRESS ); + } + return 1; + } + + case WM_LBUTTONUP: + ReleaseCapture(); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE ); + return 0; + case WM_RBUTTONUP: + ReleaseCapture(); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE ); + return 0; + case WM_MBUTTONUP: + ReleaseCapture(); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_MIDDLE, GLFW_RELEASE ); + return 0; + case WM_XBUTTONUP: + { + if( HIWORD(wParam) == XBUTTON1 ) + { + ReleaseCapture(); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_4, GLFW_RELEASE ); + } + else if( HIWORD(wParam) == XBUTTON2 ) + { + ReleaseCapture(); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_5, GLFW_RELEASE ); + } + return 1; + } + + case WM_MOUSEMOVE: + { + int NewMouseX, NewMouseY; + + // Get signed (!) mouse position + NewMouseX = (int)((short)LOWORD(lParam)); + NewMouseY = (int)((short)HIWORD(lParam)); + + if( NewMouseX != _glfwInput.OldMouseX || + NewMouseY != _glfwInput.OldMouseY ) + { + if( _glfwWin.mouseLock ) + { + _glfwInput.MousePosX += NewMouseX - + _glfwInput.OldMouseX; + _glfwInput.MousePosY += NewMouseY - + _glfwInput.OldMouseY; + } + else + { + _glfwInput.MousePosX = NewMouseX; + _glfwInput.MousePosY = NewMouseY; + } + _glfwInput.OldMouseX = NewMouseX; + _glfwInput.OldMouseY = NewMouseY; + _glfwInput.MouseMoved = GL_TRUE; + + if( _glfwWin.mousePosCallback ) + { + _glfwWin.mousePosCallback( _glfwInput.MousePosX, + _glfwInput.MousePosY ); + } + } + return 0; + } + + case WM_MOUSEWHEEL: + { + // WM_MOUSEWHEEL is not supported under Windows 95 + if( _glfwLibrary.Sys.winVer != _GLFW_WIN_95 ) + { + wheelDelta = (((int)wParam) >> 16) / WHEEL_DELTA; + _glfwInput.WheelPos += wheelDelta; + if( _glfwWin.mouseWheelCallback ) + { + _glfwWin.mouseWheelCallback( _glfwInput.WheelPos ); + } + return 0; + } + break; + } + + case WM_SIZE: + { + _glfwWin.width = LOWORD(lParam); + _glfwWin.height = HIWORD(lParam); + + // If the mouse is locked, update the clipping rect + if( _glfwWin.mouseLock ) + { + RECT ClipWindowRect; + if( GetWindowRect( _glfwWin.window, &ClipWindowRect ) ) + { + ClipCursor( &ClipWindowRect ); + } + } + + if( _glfwWin.windowSizeCallback ) + { + _glfwWin.windowSizeCallback( LOWORD(lParam), HIWORD(lParam) ); + } + return 0; + } + + case WM_MOVE: + { + // If the mouse is locked, update the clipping rect + if( _glfwWin.mouseLock ) + { + RECT ClipWindowRect; + if( GetWindowRect( _glfwWin.window, &ClipWindowRect ) ) + { + ClipCursor( &ClipWindowRect ); + } + } + return 0; + } + + // Was the window contents damaged? + case WM_PAINT: + { + if( _glfwWin.windowRefreshCallback ) + { + _glfwWin.windowRefreshCallback(); + } + break; + } + + case WM_DISPLAYCHANGE: + { + // TODO: Do stuff here. + + break; + } + } + + // Pass all unhandled messages to DefWindowProc + return DefWindowProc( hWnd, uMsg, wParam, lParam ); +} + + +//======================================================================== +// Translate client window size to full window size (including window borders) +//======================================================================== + +static void getFullWindowSize( int clientWidth, int clientHeight, + int *fullWidth, int *fullHeight ) +{ + RECT rect; + + // Create a window rectangle + rect.left = (long)0; + rect.right = (long)clientWidth - 1; + rect.top = (long)0; + rect.bottom = (long)clientHeight - 1; + + // Adjust according to window styles + AdjustWindowRectEx( &rect, _glfwWin.dwStyle, FALSE, _glfwWin.dwExStyle ); + + // Calculate width and height of full window + *fullWidth = rect.right - rect.left + 1; + *fullHeight = rect.bottom - rect.top + 1; +} + + +//======================================================================== +// Initialize WGL-specific extensions +// This function is called once before initial context creation, i.e. before +// any WGL extensions could be present. This is done in order to have both +// extension variable clearing and loading in the same place, hopefully +// decreasing the possibility of forgetting to add one without the other. +//======================================================================== + +static void initWGLExtensions( void ) +{ + // This needs to include every function pointer loaded below + _glfwWin.SwapIntervalEXT = NULL; + _glfwWin.GetPixelFormatAttribivARB = NULL; + _glfwWin.GetExtensionsStringARB = NULL; + _glfwWin.GetExtensionsStringEXT = NULL; + _glfwWin.CreateContextAttribsARB = NULL; + + // This needs to include every extension used below except for + // WGL_ARB_extensions_string and WGL_EXT_extensions_string + _glfwWin.has_WGL_EXT_swap_control = GL_FALSE; + _glfwWin.has_WGL_ARB_pixel_format = GL_FALSE; + _glfwWin.has_WGL_ARB_multisample = GL_FALSE; + _glfwWin.has_WGL_ARB_create_context = GL_FALSE; + + _glfwWin.GetExtensionsStringEXT = (WGLGETEXTENSIONSSTRINGEXT_T) + wglGetProcAddress( "wglGetExtensionsStringEXT" ); + if( !_glfwWin.GetExtensionsStringEXT ) + { + _glfwWin.GetExtensionsStringARB = (WGLGETEXTENSIONSSTRINGARB_T) + wglGetProcAddress( "wglGetExtensionsStringARB" ); + if( !_glfwWin.GetExtensionsStringARB ) + { + return; + } + } + + if( _glfwPlatformExtensionSupported( "WGL_ARB_multisample" ) ) + { + _glfwWin.has_WGL_ARB_multisample = GL_TRUE; + } + + if( _glfwPlatformExtensionSupported( "WGL_ARB_create_context" ) ) + { + _glfwWin.has_WGL_ARB_create_context = GL_TRUE; + _glfwWin.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) + wglGetProcAddress( "wglCreateContextAttribsARB" ); + } + + if( _glfwPlatformExtensionSupported( "WGL_EXT_swap_control" ) ) + { + _glfwWin.has_WGL_EXT_swap_control = GL_TRUE; + _glfwWin.SwapIntervalEXT = (WGLSWAPINTERVALEXT_T) + wglGetProcAddress( "wglSwapIntervalEXT" ); + } + + if( _glfwPlatformExtensionSupported( "WGL_ARB_pixel_format" ) ) + { + _glfwWin.has_WGL_ARB_pixel_format = GL_TRUE; + _glfwWin.GetPixelFormatAttribivARB = (WGLGETPIXELFORMATATTRIBIVARB_T) + wglGetProcAddress( "wglGetPixelFormatAttribivARB" ); + } +} + + +//======================================================================== +// Registers the GLFW window class +//======================================================================== + +static ATOM registerWindowClass( void ) +{ + WNDCLASS wc; + + // Set window class parameters + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw on... + wc.lpfnWndProc = (WNDPROC)windowProc; // Message handler + wc.cbClsExtra = 0; // No extra class data + wc.cbWndExtra = 0; // No extra window data + wc.hInstance = _glfwLibrary.instance; // Set instance + wc.hCursor = LoadCursor( NULL, IDC_ARROW ); // Load arrow pointer + wc.hbrBackground = NULL; // No background + wc.lpszMenuName = NULL; // No menu + wc.lpszClassName = _GLFW_WNDCLASSNAME; // Set class name + + // Load user-provided icon if available + wc.hIcon = LoadIcon( _glfwLibrary.instance, "GLFW_ICON" ); + if( !wc.hIcon ) + { + // Load default icon + wc.hIcon = LoadIcon( NULL, IDI_WINLOGO ); + } + + return RegisterClass( &wc ); +} + + +//======================================================================== +// Returns the closest matching pixel format, or zero on error +//======================================================================== + +static int choosePixelFormat( const _GLFWfbconfig *fbconfig ) +{ + unsigned int fbcount; + int pixelFormat; + _GLFWfbconfig *fbconfigs; + const _GLFWfbconfig *closest; + + fbconfigs = getFBConfigs( &fbcount ); + if( !fbconfigs ) + { + fprintf( stderr, "Failed to find any usable GLFWFBConfigs\n" ); + return 0; + } + + closest = _glfwChooseFBConfig( fbconfig, fbconfigs, fbcount ); + if( !closest ) + { + fprintf( stderr, "Failed to select a GLFWFBConfig from the alternatives\n" ); + free( fbconfigs ); + return 0; + } + + pixelFormat = (int) closest->platformID; + + free( fbconfigs ); + fbconfigs = NULL; + closest = NULL; + + return pixelFormat; +} + + +//======================================================================== +// Creates the GLFW window and rendering context +//======================================================================== + +static int createWindow( const _GLFWwndconfig *wndconfig, + const _GLFWfbconfig *fbconfig ) +{ + DWORD dwStyle, dwExStyle; + int pixelFormat, fullWidth, fullHeight; + RECT wa; + POINT pos; + + _glfwWin.DC = NULL; + _glfwWin.context = NULL; + _glfwWin.window = NULL; + + // Set common window styles + dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; + dwExStyle = WS_EX_APPWINDOW; + + // Set window style, depending on fullscreen mode + if( _glfwWin.fullscreen ) + { + dwStyle |= WS_POPUP; + + // Here's a trick for helping us getting window focus + // (SetForegroundWindow doesn't work properly under + // Win98/ME/2K/.NET/+) + /* + if( _glfwLibrary.Sys.WinVer != _GLFW_WIN_95 && + _glfwLibrary.Sys.WinVer != _GLFW_WIN_NT4 && + _glfwLibrary.Sys.WinVer != _GLFW_WIN_XP ) + { + dwStyle |= WS_MINIMIZE; + } + */ + } + else + { + dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; + + if( !wndconfig->windowNoResize ) + { + dwStyle |= ( WS_MAXIMIZEBOX | WS_SIZEBOX ); + dwExStyle |= WS_EX_WINDOWEDGE; + } + } + + // Remember window styles (used by getFullWindowSize) + _glfwWin.dwStyle = dwStyle; + _glfwWin.dwExStyle = dwExStyle; + + // Adjust window size for frame and title bar + getFullWindowSize( _glfwWin.width, _glfwWin.height, &fullWidth, &fullHeight ); + + // Adjust window position to working area (e.g. if the task bar is at + // the top of the display). Fullscreen windows are always opened in + // the upper left corner regardless of the desktop working area. + if( _glfwWin.fullscreen ) + { + wa.left = wa.top = 0; + } + else + { + SystemParametersInfo( SPI_GETWORKAREA, 0, &wa, 0 ); + } + + _glfwWin.window = CreateWindowEx( _glfwWin.dwExStyle, // Extended style + _GLFW_WNDCLASSNAME, // Class name + "GLFW Window", // Window title + _glfwWin.dwStyle, // Defined window style + wa.left, wa.top, // Window position + fullWidth, // Decorated window width + fullHeight, // Decorated window height + NULL, // No parent window + NULL, // No menu + _glfwLibrary.instance, // Instance + NULL ); // Nothing to WM_CREATE + + if( !_glfwWin.window ) + { + fprintf( stderr, "Unable to create Win32 window\n" ); + return GL_FALSE; + } + + _glfwWin.DC = GetDC( _glfwWin.window ); + if( !_glfwWin.DC ) + { + fprintf( stderr, "Unable to retrieve GLFW window DC\n" ); + return GL_FALSE; + } + + pixelFormat = choosePixelFormat( fbconfig ); + if( !pixelFormat ) + { + fprintf( stderr, "Unable to find a usable pixel format\n" ); + return GL_FALSE; + } + + _glfwWin.context = createContext( _glfwWin.DC, wndconfig, pixelFormat ); + if( !_glfwWin.context ) + { + fprintf( stderr, "Unable to create OpenGL context\n" ); + return GL_FALSE; + } + + if( !wglMakeCurrent( _glfwWin.DC, _glfwWin.context ) ) + { + fprintf( stderr, "Unable to make OpenGL context current\n" ); + return GL_FALSE; + } + + initWGLExtensions(); + + // Initialize mouse position data + GetCursorPos( &pos ); + ScreenToClient( _glfwWin.window, &pos ); + _glfwInput.OldMouseX = _glfwInput.MousePosX = pos.x; + _glfwInput.OldMouseY = _glfwInput.MousePosY = pos.y; + + return GL_TRUE; +} + + +//======================================================================== +// Destroys the GLFW window and rendering context +//======================================================================== + +static void destroyWindow( void ) +{ + if( _glfwWin.context ) + { + wglMakeCurrent( NULL, NULL ); + wglDeleteContext( _glfwWin.context ); + _glfwWin.context = NULL; + } + + if( _glfwWin.DC ) + { + ReleaseDC( _glfwWin.window, _glfwWin.DC ); + _glfwWin.DC = NULL; + } + + if( _glfwWin.window ) + { + if( _glfwLibrary.Sys.winVer <= _GLFW_WIN_NT4 ) + { + // Note: Hiding the window first fixes an annoying W98/NT4 + // remaining icon bug for fullscreen displays + ShowWindow( _glfwWin.window, SW_HIDE ); + } + + DestroyWindow( _glfwWin.window ); + _glfwWin.window = NULL; + } +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Here is where the window is created, and the OpenGL rendering context is +// created +//======================================================================== + +int _glfwPlatformOpenWindow( int width, int height, + const _GLFWwndconfig *wndconfig, + const _GLFWfbconfig *fbconfig ) +{ + GLboolean recreateContext = GL_FALSE; + + // Clear platform specific GLFW window state + _glfwWin.classAtom = 0; + _glfwWin.oldMouseLockValid = GL_FALSE; + + _glfwWin.desiredRefreshRate = wndconfig->refreshRate; + + _glfwWin.classAtom = registerWindowClass(); + if( !_glfwWin.classAtom ) + { + fprintf( stderr, "Failed to register GLFW window class\n" ); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + if( _glfwWin.fullscreen ) + { + _glfwSetVideoMode( &_glfwWin.width, &_glfwWin.height, + fbconfig->redBits, fbconfig->greenBits, fbconfig->blueBits, + wndconfig->refreshRate ); + } + + initWGLExtensions(); + + if( !createWindow( wndconfig, fbconfig ) ) + { + fprintf( stderr, "Failed to create GLFW window\n" ); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + if( wndconfig->glMajor > 2 ) + { + if( !_glfwWin.has_WGL_ARB_create_context ) + { + fprintf( stderr, "OpenGL 3.0+ is not supported\n" ); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + recreateContext = GL_TRUE; + } + + if( fbconfig->samples > 0 ) + { + // We want FSAA, but can we get it? + // FSAA is not a hard constraint, so otherwise we just don't care + + if( _glfwWin.has_WGL_ARB_multisample && _glfwWin.has_WGL_ARB_pixel_format ) + { + // We appear to have both the FSAA extension and the means to ask for it + recreateContext = GL_TRUE; + } + } + + if( recreateContext ) + { + // Some window hints require us to re-create the context using WGL + // extensions retrieved through the current context, as we cannot check + // for WGL extensions or retrieve WGL entry points before we have a + // current context (actually until we have implicitly loaded the ICD) + + // Yes, this is strange, and yes, this is the proper way on Win32 + + // As Windows only allows you to set the pixel format once for a + // window, we need to destroy the current window and create a new one + // to be able to use the new pixel format + + // Technically, it may be possible to keep the old window around if + // we're just creating an OpenGL 3.0+ context with the same pixel + // format, but it's not worth the potential compatibility problems + + destroyWindow(); + + if( !createWindow( wndconfig, fbconfig ) ) + { + fprintf( stderr, "Unable to re-create GLFW window\n" ); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + } + + if( _glfwWin.fullscreen ) + { + // Place the window above all topmost windows + SetWindowPos( _glfwWin.window, HWND_TOPMOST, 0,0,0,0, + SWP_NOMOVE | SWP_NOSIZE ); + } + + setForegroundWindow( _glfwWin.window ); + SetFocus( _glfwWin.window ); + + return GL_TRUE; +} + + +//======================================================================== +// Properly kill the window / video display +//======================================================================== + +void _glfwPlatformCloseWindow( void ) +{ + destroyWindow(); + + if( _glfwWin.classAtom ) + { + UnregisterClass( _GLFW_WNDCLASSNAME, _glfwLibrary.instance ); + _glfwWin.classAtom = 0; + } + + if( _glfwWin.fullscreen ) + { + // Restore original desktop resolution + ChangeDisplaySettings( NULL, CDS_FULLSCREEN ); + } +} + + +//======================================================================== +// Set the window title +//======================================================================== + +void _glfwPlatformSetWindowTitle( const char *title ) +{ + (void) SetWindowText( _glfwWin.window, title ); +} + + +//======================================================================== +// Set the window size. +//======================================================================== + +void _glfwPlatformSetWindowSize( int width, int height ) +{ + int bpp, mode = 0, refresh; + int sizechanged = GL_FALSE; + GLint drawbuffer; + GLfloat clearcolor[4]; + + if( _glfwWin.fullscreen ) + { + // Get some info about the current mode + + DEVMODE dm; + + // Get current BPP settings + dm.dmSize = sizeof( DEVMODE ); + if( EnumDisplaySettings( NULL, _glfwWin.modeID, &dm ) ) + { + // Get bpp + bpp = dm.dmBitsPerPel; + + // Get closest match for target video mode + refresh = _glfwWin.desiredRefreshRate; + mode = _glfwGetClosestVideoModeBPP( &width, &height, &bpp, + &refresh ); + } + else + { + mode = _glfwWin.modeID; + } + } + else + { + // If we are in windowed mode, adjust the window size to + // compensate for window decorations + getFullWindowSize( width, height, &width, &height ); + } + + // Change window size before changing fullscreen mode? + if( _glfwWin.fullscreen && (width > _glfwWin.width) ) + { + SetWindowPos( _glfwWin.window, HWND_TOP, 0, 0, width, height, + SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER ); + sizechanged = GL_TRUE; + } + + // Change fullscreen video mode? + if( _glfwWin.fullscreen && mode != _glfwWin.modeID ) + { + _glfwSetVideoModeMODE( mode ); + + // Clear the front buffer to black (avoid ugly desktop remains in + // our OpenGL window) + glGetIntegerv( GL_DRAW_BUFFER, &drawbuffer ); + glGetFloatv( GL_COLOR_CLEAR_VALUE, clearcolor ); + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); + glClear( GL_COLOR_BUFFER_BIT ); + if( drawbuffer == GL_BACK ) + { + _glfw_SwapBuffers( _glfwWin.DC ); + } + glClearColor( clearcolor[0], clearcolor[1], clearcolor[2], + clearcolor[3] ); + } + + // Set window size (if not already changed) + if( !sizechanged ) + { + SetWindowPos( _glfwWin.window, HWND_TOP, 0, 0, width, height, + SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER ); + } +} + + +//======================================================================== +// Set the window position +//======================================================================== + +void _glfwPlatformSetWindowPos( int x, int y ) +{ + (void) SetWindowPos( _glfwWin.window, HWND_TOP, x, y, 0, 0, + SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER ); +} + + +//======================================================================== +// Window iconification +//======================================================================== + +void _glfwPlatformIconifyWindow( void ) +{ + // Iconify window + CloseWindow( _glfwWin.window ); + _glfwWin.iconified = GL_TRUE; + + // If we are in fullscreen mode we need to change video modes + if( _glfwWin.fullscreen ) + { + // Change display settings to the desktop resolution + ChangeDisplaySettings( NULL, CDS_FULLSCREEN ); + } + + // Unlock mouse + if( !_glfwWin.oldMouseLockValid ) + { + _glfwWin.oldMouseLock = _glfwWin.mouseLock; + _glfwWin.oldMouseLockValid = GL_TRUE; + glfwEnable( GLFW_MOUSE_CURSOR ); + } +} + + +//======================================================================== +// Window un-iconification +//======================================================================== + +void _glfwPlatformRestoreWindow( void ) +{ + // If we are in fullscreen mode we need to change video modes + if( _glfwWin.fullscreen ) + { + // Change display settings to the user selected mode + _glfwSetVideoModeMODE( _glfwWin.modeID ); + } + + // Un-iconify window + OpenIcon( _glfwWin.window ); + + // Make sure that our window ends up on top of things + ShowWindow( _glfwWin.window, SW_SHOW ); + setForegroundWindow( _glfwWin.window ); + SetFocus( _glfwWin.window ); + + // Window is no longer iconified + _glfwWin.iconified = GL_FALSE; + + // Lock mouse, if necessary + if( _glfwWin.oldMouseLockValid && _glfwWin.oldMouseLock ) + { + glfwDisable( GLFW_MOUSE_CURSOR ); + } + _glfwWin.oldMouseLockValid = GL_FALSE; +} + + +//======================================================================== +// Swap buffers (double-buffering) +//======================================================================== + +void _glfwPlatformSwapBuffers( void ) +{ + _glfw_SwapBuffers( _glfwWin.DC ); +} + + +//======================================================================== +// Set double buffering swap interval +//======================================================================== + +void _glfwPlatformSwapInterval( int interval ) +{ + if( _glfwWin.has_WGL_EXT_swap_control ) + { + _glfwWin.SwapIntervalEXT( interval ); + } +} + + +//======================================================================== +// Write back window parameters into GLFW window structure +//======================================================================== + +void _glfwPlatformRefreshWindowParams( void ) +{ + PIXELFORMATDESCRIPTOR pfd; + DEVMODE dm; + int pixelFormat, mode; + + // Obtain a detailed description of current pixel format + pixelFormat = _glfw_GetPixelFormat( _glfwWin.DC ); + + if( _glfwWin.has_WGL_ARB_pixel_format ) + { + if( getPixelFormatAttrib( pixelFormat, WGL_ACCELERATION_ARB ) != + WGL_NO_ACCELERATION_ARB ) + { + _glfwWin.accelerated = GL_TRUE; + } + else + { + _glfwWin.accelerated = GL_FALSE; + } + + _glfwWin.redBits = getPixelFormatAttrib( pixelFormat, WGL_RED_BITS_ARB ); + _glfwWin.greenBits = getPixelFormatAttrib( pixelFormat, WGL_GREEN_BITS_ARB ); + _glfwWin.blueBits = getPixelFormatAttrib( pixelFormat, WGL_BLUE_BITS_ARB ); + + _glfwWin.alphaBits = getPixelFormatAttrib( pixelFormat, WGL_ALPHA_BITS_ARB ); + _glfwWin.depthBits = getPixelFormatAttrib( pixelFormat, WGL_DEPTH_BITS_ARB ); + _glfwWin.stencilBits = getPixelFormatAttrib( pixelFormat, WGL_STENCIL_BITS_ARB ); + + _glfwWin.accumRedBits = getPixelFormatAttrib( pixelFormat, WGL_ACCUM_RED_BITS_ARB ); + _glfwWin.accumGreenBits = getPixelFormatAttrib( pixelFormat, WGL_ACCUM_GREEN_BITS_ARB ); + _glfwWin.accumBlueBits = getPixelFormatAttrib( pixelFormat, WGL_ACCUM_BLUE_BITS_ARB ); + _glfwWin.accumAlphaBits = getPixelFormatAttrib( pixelFormat, WGL_ACCUM_ALPHA_BITS_ARB ); + + _glfwWin.auxBuffers = getPixelFormatAttrib( pixelFormat, WGL_AUX_BUFFERS_ARB ); + _glfwWin.stereo = getPixelFormatAttrib( pixelFormat, WGL_STEREO_ARB ) ? GL_TRUE : GL_FALSE; + + if( _glfwWin.has_WGL_ARB_multisample ) + { + _glfwWin.samples = getPixelFormatAttrib( pixelFormat, WGL_SAMPLES_ARB ); + // Should we force 1 to 0 here for consistency, or keep 1 for transparency? + } + else + { + _glfwWin.samples = 0; + } + } + else + { + _glfw_DescribePixelFormat( _glfwWin.DC, pixelFormat, + sizeof(PIXELFORMATDESCRIPTOR), &pfd ); + + // Is current OpenGL context accelerated? + _glfwWin.accelerated = (pfd.dwFlags & PFD_GENERIC_ACCELERATED) || + !(pfd.dwFlags & PFD_GENERIC_FORMAT) ? 1 : 0; + + // "Standard" window parameters + _glfwWin.redBits = pfd.cRedBits; + _glfwWin.greenBits = pfd.cGreenBits; + _glfwWin.blueBits = pfd.cBlueBits; + _glfwWin.alphaBits = pfd.cAlphaBits; + _glfwWin.depthBits = pfd.cDepthBits; + _glfwWin.stencilBits = pfd.cStencilBits; + _glfwWin.accumRedBits = pfd.cAccumRedBits; + _glfwWin.accumGreenBits = pfd.cAccumGreenBits; + _glfwWin.accumBlueBits = pfd.cAccumBlueBits; + _glfwWin.accumAlphaBits = pfd.cAccumAlphaBits; + _glfwWin.auxBuffers = pfd.cAuxBuffers; + _glfwWin.stereo = (pfd.dwFlags & PFD_STEREO) ? GL_TRUE : GL_FALSE; + + // If we don't have WGL_ARB_pixel_format then we can't have created a + // multisampling context, so it's safe to hardcode zero here + _glfwWin.samples = 0; + } + + // Get refresh rate + mode = _glfwWin.fullscreen ? _glfwWin.modeID : ENUM_CURRENT_SETTINGS; + dm.dmSize = sizeof( DEVMODE ); + + if( EnumDisplaySettings( NULL, mode, &dm ) ) + { + _glfwWin.refreshRate = dm.dmDisplayFrequency; + if( _glfwWin.refreshRate <= 1 ) + { + _glfwWin.refreshRate = 0; + } + } + else + { + _glfwWin.refreshRate = 0; + } +} + + +//======================================================================== +// Poll for new window and input events +//======================================================================== + +void _glfwPlatformPollEvents( void ) +{ + MSG msg; + int winclosed = GL_FALSE; + + // Flag: mouse was not moved (will be changed by _glfwGetNextEvent if + // there was a mouse move event) + _glfwInput.MouseMoved = GL_FALSE; + if( _glfwWin.mouseLock ) + { + _glfwInput.OldMouseX = _glfwWin.width/2; + _glfwInput.OldMouseY = _glfwWin.height/2; + } + else + { + _glfwInput.OldMouseX = _glfwInput.MousePosX; + _glfwInput.OldMouseY = _glfwInput.MousePosY; + } + + // Check for new window messages + while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) + { + switch( msg.message ) + { + // QUIT-message (from close window)? + case WM_QUIT: + winclosed = GL_TRUE; + break; + + // Ok, send it to the window message handler + default: + DispatchMessage( &msg ); + break; + } + } + + // LSHIFT/RSHIFT fixup (keys tend to "stick" without this fix) + // This is the only async event handling in GLFW, but it solves some + // nasty problems. + // Caveat: Does not work under Win 9x/ME. + if( _glfwLibrary.Sys.winVer >= _GLFW_WIN_NT4 ) + { + int lshift_down, rshift_down; + + // Get current state of left and right shift keys + lshift_down = (GetAsyncKeyState( VK_LSHIFT ) >> 15) & 1; + rshift_down = (GetAsyncKeyState( VK_RSHIFT ) >> 15) & 1; + + // See if this differs from our belief of what has happened + // (we only have to check for lost key up events) + if( !lshift_down && _glfwInput.Key[ GLFW_KEY_LSHIFT ] == 1 ) + { + _glfwInputKey( GLFW_KEY_LSHIFT, GLFW_RELEASE ); + } + if( !rshift_down && _glfwInput.Key[ GLFW_KEY_RSHIFT ] == 1 ) + { + _glfwInputKey( GLFW_KEY_RSHIFT, GLFW_RELEASE ); + } + } + + // Did we have mouse movement in locked cursor mode? + if( _glfwInput.MouseMoved && _glfwWin.mouseLock ) + { + _glfwPlatformSetMouseCursorPos( _glfwWin.width / 2, + _glfwWin.height / 2 ); + } + + // Was there a window close request? + if( winclosed && _glfwWin.windowCloseCallback ) + { + // Check if the program wants us to close the window + winclosed = _glfwWin.windowCloseCallback(); + } + if( winclosed ) + { + glfwCloseWindow(); + } +} + + +//======================================================================== +// _glfwPlatformWaitEvents() - Wait for new window and input events +//======================================================================== + +void _glfwPlatformWaitEvents( void ) +{ + WaitMessage(); + + _glfwPlatformPollEvents(); +} + + +//======================================================================== +// Hide mouse cursor (lock it) +//======================================================================== + +void _glfwPlatformHideMouseCursor( void ) +{ + RECT ClipWindowRect; + + ShowCursor( FALSE ); + + // Clip cursor to the window + if( GetWindowRect( _glfwWin.window, &ClipWindowRect ) ) + { + ClipCursor( &ClipWindowRect ); + } + + // Capture cursor to user window + SetCapture( _glfwWin.window ); +} + + +//======================================================================== +// Show mouse cursor (unlock it) +//======================================================================== + +void _glfwPlatformShowMouseCursor( void ) +{ + // Un-capture cursor + ReleaseCapture(); + + // Release the cursor from the window + ClipCursor( NULL ); + + ShowCursor( TRUE ); +} + + +//======================================================================== +// Set physical mouse cursor position +//======================================================================== + +void _glfwPlatformSetMouseCursorPos( int x, int y ) +{ + POINT pos; + + // Convert client coordinates to screen coordinates + pos.x = x; + pos.y = y; + ClientToScreen( _glfwWin.window, &pos ); + + SetCursorPos( pos.x, pos.y ); +} + diff --git a/lib/window.c b/lib/window.c new file mode 100644 index 00000000..cc6adcd9 --- /dev/null +++ b/lib/window.c @@ -0,0 +1,1030 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: Any +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +static int Max(int a, int b) +{ + return (a > b) ? a : b; +} + +//======================================================================== +// Clear all open window hints +//======================================================================== + +void _glfwClearWindowHints( void ) +{ + memset( &_glfwLibrary.hints, 0, sizeof( _glfwLibrary.hints ) ); + _glfwLibrary.hints.glMajor = 1; +} + + +//======================================================================== +// Handle the input tracking part of window deactivation +//======================================================================== + +void _glfwInputDeactivation( void ) +{ + int i; + + // Release all keyboard keys + for( i = 0; i <= GLFW_KEY_LAST; i ++ ) + { + if( _glfwInput.Key[ i ] == GLFW_PRESS ) + { + _glfwInputKey( i, GLFW_RELEASE ); + } + } + + // Release all mouse buttons + for( i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i ++ ) + { + if( _glfwInput.MouseButton[ i ] == GLFW_PRESS ) + { + _glfwInputMouseClick( i, GLFW_RELEASE ); + } + } +} + + +//======================================================================== +// _glfwClearInput() - Clear all input state +//======================================================================== + +void _glfwClearInput( void ) +{ + int i; + + // Release all keyboard keys + for( i = 0; i <= GLFW_KEY_LAST; i ++ ) + { + _glfwInput.Key[ i ] = GLFW_RELEASE; + } + + // Clear last character + _glfwInput.LastChar = 0; + + // Release all mouse buttons + for( i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i ++ ) + { + _glfwInput.MouseButton[ i ] = GLFW_RELEASE; + } + + // Set mouse position to (0,0) + _glfwInput.MousePosX = 0; + _glfwInput.MousePosY = 0; + + // Set mouse wheel position to 0 + _glfwInput.WheelPos = 0; + + // The default is to use non sticky keys and mouse buttons + _glfwInput.StickyKeys = GL_FALSE; + _glfwInput.StickyMouseButtons = GL_FALSE; + + // The default is to disable key repeat + _glfwInput.KeyRepeat = GL_FALSE; +} + + +//======================================================================== +// _glfwInputKey() - Register keyboard activity +//======================================================================== + +void _glfwInputKey( int key, int action ) +{ + int keyrepeat = 0; + + if( key < 0 || key > GLFW_KEY_LAST ) + { + return; + } + + // Are we trying to release an already released key? + if( action == GLFW_RELEASE && _glfwInput.Key[ key ] != GLFW_PRESS ) + { + return; + } + + // Register key action + if( action == GLFW_RELEASE && _glfwInput.StickyKeys ) + { + _glfwInput.Key[ key ] = GLFW_STICK; + } + else + { + keyrepeat = (_glfwInput.Key[ key ] == GLFW_PRESS) && + (action == GLFW_PRESS); + _glfwInput.Key[ key ] = (char) action; + } + + // Call user callback function + if( _glfwWin.keyCallback && (_glfwInput.KeyRepeat || !keyrepeat) ) + { + _glfwWin.keyCallback( key, action ); + } +} + + +//======================================================================== +// Register (keyboard) character activity +//======================================================================== + +void _glfwInputChar( int character, int action ) +{ + int keyrepeat = 0; + + // Valid Unicode (ISO 10646) character? + if( !( (character >= 32 && character <= 126) || character >= 160 ) ) + { + return; + } + + // Is this a key repeat? + if( action == GLFW_PRESS && _glfwInput.LastChar == character ) + { + keyrepeat = 1; + } + + // Store this character as last character (or clear it, if released) + if( action == GLFW_PRESS ) + { + _glfwInput.LastChar = character; + } + else + { + _glfwInput.LastChar = 0; + } + + if( action != GLFW_PRESS ) + { + // This intentionally breaks release notifications for Unicode + // characters, partly to see if anyone cares but mostly because it's + // a nonsensical concept to begin with + // + // It will remain broken either until its removal in the 3.0 API or + // until someone explains, in a way that makes sense to people outside + // the US and Scandinavia, what "Unicode character up" actually means + // + // If what you want is "physical key up" then you should be using the + // key functions and/or the key callback, NOT the Unicode input + // + // However, if your particular application uses this misfeature for... + // something, you can re-enable it by removing this if-statement + return; + } + + if( _glfwWin.charCallback && (_glfwInput.KeyRepeat || !keyrepeat) ) + { + _glfwWin.charCallback( character, action ); + } +} + + +//======================================================================== +// _glfwInputMouseClick() - Register mouse button clicks +//======================================================================== + +void _glfwInputMouseClick( int button, int action ) +{ + if( button >= 0 && button <= GLFW_MOUSE_BUTTON_LAST ) + { + // Register mouse button action + if( action == GLFW_RELEASE && _glfwInput.StickyMouseButtons ) + { + _glfwInput.MouseButton[ button ] = GLFW_STICK; + } + else + { + _glfwInput.MouseButton[ button ] = (char) action; + } + + // Call user callback function + if( _glfwWin.mouseButtonCallback ) + { + _glfwWin.mouseButtonCallback( button, action ); + } + } +} + + +//======================================================================== +// Return the available framebuffer config closest to the desired values +// This is based on the manual GLX Visual selection from 2.6 +//======================================================================== + +const _GLFWfbconfig *_glfwChooseFBConfig( const _GLFWfbconfig *desired, + const _GLFWfbconfig *alternatives, + unsigned int count ) +{ + unsigned int i; + unsigned int missing, leastMissing = UINT_MAX; + unsigned int colorDiff, leastColorDiff = UINT_MAX; + unsigned int extraDiff, leastExtraDiff = UINT_MAX; + GLboolean desiresColor = GL_FALSE; + const _GLFWfbconfig *current; + const _GLFWfbconfig *closest = NULL; + + // Cache some long-winded preferences + + if( desired->redBits || desired->greenBits || desired->blueBits || + desired->alphaBits ) + { + desiresColor = GL_TRUE; + } + + for( i = 0; i < count; i++ ) + { + current = alternatives + i; + + if( desired->stereo > 0 && current->stereo == 0 ) + { + // Stereo is a hard constraint + continue; + } + + // Count number of missing buffers + { + missing = 0; + + if( desired->alphaBits > 0 && current->alphaBits == 0 ) + { + missing++; + } + + if( desired->depthBits > 0 && current->depthBits == 0 ) + { + missing++; + } + + if( desired->stencilBits > 0 && current->stencilBits == 0 ) + { + missing++; + } + + if( desired->auxBuffers > 0 && current->auxBuffers < desired->auxBuffers ) + { + missing += desired->auxBuffers - current->auxBuffers; + } + + if( desired->samples > 0 && current->samples == 0 ) + { + // Technically, several multisampling buffers could be + // involved, but that's a lower level implementation detail and + // not important to us here, so we count them as one + missing++; + } + } + + // These polynomials make many small channel size differences matter + // less than one large channel size difference + + // Calculate color channel size difference value + { + colorDiff = 0; + + if ( desired->redBits > 0 ) + { + colorDiff += ( desired->redBits - current->redBits ) * + ( desired->redBits - current->redBits ); + } + + if ( desired->greenBits > 0 ) + { + colorDiff += ( desired->greenBits - current->greenBits ) * + ( desired->greenBits - current->greenBits ); + } + + if ( desired->blueBits > 0 ) + { + colorDiff += ( desired->blueBits - current->blueBits ) * + ( desired->blueBits - current->blueBits ); + } + } + + // Calculate non-color channel size difference value + { + extraDiff = 0; + + if( desired->alphaBits > 0 ) + { + extraDiff += ( desired->alphaBits - current->alphaBits ) * + ( desired->alphaBits - current->alphaBits ); + } + + if( desired->depthBits > 0 ) + { + extraDiff += ( desired->depthBits - current->depthBits ) * + ( desired->depthBits - current->depthBits ); + } + + if( desired->stencilBits > 0 ) + { + extraDiff += ( desired->stencilBits - current->stencilBits ) * + ( desired->stencilBits - current->stencilBits ); + } + + if( desired->accumRedBits > 0 ) + { + extraDiff += ( desired->accumRedBits - current->accumRedBits ) * + ( desired->accumRedBits - current->accumRedBits ); + } + + if( desired->accumGreenBits > 0 ) + { + extraDiff += ( desired->accumGreenBits - current->accumGreenBits ) * + ( desired->accumGreenBits - current->accumGreenBits ); + } + + if( desired->accumBlueBits > 0 ) + { + extraDiff += ( desired->accumBlueBits - current->accumBlueBits ) * + ( desired->accumBlueBits - current->accumBlueBits ); + } + + if( desired->accumAlphaBits > 0 ) + { + extraDiff += ( desired->accumAlphaBits - current->accumAlphaBits ) * + ( desired->accumAlphaBits - current->accumAlphaBits ); + } + + if( desired->samples > 0 ) + { + extraDiff += ( desired->samples - current->samples ) * + ( desired->samples - current->samples ); + } + } + + // Figure out if the current one is better than the best one found so far + + if( missing < leastMissing ) + { + closest = current; + } + else if( missing == leastMissing ) + { + if( desiresColor ) + { + if( ( colorDiff < leastColorDiff ) || + ( colorDiff == leastColorDiff && extraDiff < leastExtraDiff ) ) + { + closest = current; + } + } + else + { + if( ( extraDiff < leastExtraDiff ) || + ( extraDiff == leastExtraDiff && colorDiff < leastColorDiff ) ) + { + closest = current; + } + } + } + + if( current == closest ) + { + leastMissing = missing; + leastColorDiff = colorDiff; + leastExtraDiff = extraDiff; + } + } + + return closest; +} + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// Create the GLFW window and its associated context +//======================================================================== + +GLFWAPI int glfwOpenWindow( int width, int height, + int redbits, int greenbits, int bluebits, int alphabits, + int depthbits, int stencilbits, int mode ) +{ + _GLFWfbconfig fbconfig; + _GLFWwndconfig wndconfig; + + // Is GLFW initialized? + if( !_glfwInitialized || _glfwWin.opened ) + { + return GL_FALSE; + } + + // Set up desired framebuffer config + fbconfig.redBits = Max( redbits, 0 ); + fbconfig.greenBits = Max( greenbits, 0 ); + fbconfig.blueBits = Max( bluebits, 0 ); + fbconfig.alphaBits = Max( alphabits, 0 ); + fbconfig.depthBits = Max( depthbits, 0 ); + fbconfig.stencilBits = Max( stencilbits, 0 ); + fbconfig.accumRedBits = Max( _glfwLibrary.hints.accumRedBits, 0 ); + fbconfig.accumGreenBits = Max( _glfwLibrary.hints.accumGreenBits, 0 ); + fbconfig.accumBlueBits = Max( _glfwLibrary.hints.accumBlueBits, 0 ); + fbconfig.accumAlphaBits = Max( _glfwLibrary.hints.accumAlphaBits, 0 ); + fbconfig.auxBuffers = Max( _glfwLibrary.hints.auxBuffers, 0 ); + fbconfig.stereo = _glfwLibrary.hints.stereo ? GL_TRUE : GL_FALSE; + fbconfig.samples = Max( _glfwLibrary.hints.samples, 0 ); + + // Set up desired window config + wndconfig.mode = mode; + wndconfig.refreshRate = Max( _glfwLibrary.hints.refreshRate, 0 ); + wndconfig.windowNoResize = _glfwLibrary.hints.windowNoResize ? GL_TRUE : GL_FALSE; + wndconfig.glMajor = Max( _glfwLibrary.hints.glMajor, 1 ); + wndconfig.glMinor = Max( _glfwLibrary.hints.glMinor, 0 ); + wndconfig.glForward = _glfwLibrary.hints.glForward ? GL_TRUE : GL_FALSE; + wndconfig.glDebug = _glfwLibrary.hints.glDebug ? GL_TRUE : GL_FALSE; + wndconfig.glProfile = _glfwLibrary.hints.glProfile; + + if( wndconfig.glMajor == 1 && wndconfig.glMinor > 5 ) + { + // OpenGL 1.x series ended with version 1.5 + return GL_FALSE; + } + else if( wndconfig.glMajor == 2 && wndconfig.glMinor > 1 ) + { + // OpenGL 2.x series ended with version 2.1 + return GL_FALSE; + } + else if( wndconfig.glMajor == 3 && wndconfig.glMinor > 3 ) + { + // OpenGL 3.x series ended with version 3.3 + return GL_FALSE; + } + else + { + // For now, let everything else through + } + + if( wndconfig.glProfile && + ( wndconfig.glMajor < 3 || ( wndconfig.glMajor == 3 && wndconfig.glMinor < 2 ) ) ) + { + // Context profiles are only defined for OpenGL version 3.2 and above + return GL_FALSE; + } + + if( wndconfig.glForward && wndconfig.glMajor < 3 ) + { + // Forward-compatible contexts are only defined for OpenGL version 3.0 and above + return GL_FALSE; + } + + // Clear for next open call + _glfwClearWindowHints(); + + // Check input arguments + if( mode != GLFW_WINDOW && mode != GLFW_FULLSCREEN ) + { + return GL_FALSE; + } + + // Clear GLFW window state + _glfwWin.active = GL_TRUE; + _glfwWin.iconified = GL_FALSE; + _glfwWin.mouseLock = GL_FALSE; + _glfwWin.autoPollEvents = GL_TRUE; + _glfwClearInput(); + + // Unregister all callback functions + _glfwWin.windowSizeCallback = NULL; + _glfwWin.windowCloseCallback = NULL; + _glfwWin.windowRefreshCallback = NULL; + _glfwWin.keyCallback = NULL; + _glfwWin.charCallback = NULL; + _glfwWin.mousePosCallback = NULL; + _glfwWin.mouseButtonCallback = NULL; + _glfwWin.mouseWheelCallback = NULL; + + // Check width & height + if( width > 0 && height <= 0 ) + { + // Set the window aspect ratio to 4:3 + height = (width * 3) / 4; + } + else if( width <= 0 && height > 0 ) + { + // Set the window aspect ratio to 4:3 + width = (height * 4) / 3; + } + else if( width <= 0 && height <= 0 ) + { + // Default window size + width = 640; + height = 480; + } + + // Remember window settings + _glfwWin.width = width; + _glfwWin.height = height; + _glfwWin.fullscreen = (mode == GLFW_FULLSCREEN ? GL_TRUE : GL_FALSE); + + // Platform specific window opening routine + if( !_glfwPlatformOpenWindow( width, height, &wndconfig, &fbconfig ) ) + { + return GL_FALSE; + } + + // Flag that window is now opened + _glfwWin.opened = GL_TRUE; + + // Get window parameters (such as color buffer bits etc) + _glfwPlatformRefreshWindowParams(); + + // Get OpenGL version + _glfwParseGLVersion( &_glfwWin.glMajor, &_glfwWin.glMinor, + &_glfwWin.glRevision ); + + if( _glfwWin.glMajor < wndconfig.glMajor || + ( _glfwWin.glMajor == wndconfig.glMajor && + _glfwWin.glMinor < wndconfig.glMinor ) ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Do we have non-power-of-two textures (added to core in version 2.0)? + _glfwWin.has_GL_ARB_texture_non_power_of_two = + ( _glfwWin.glMajor >= 2 ) || + glfwExtensionSupported( "GL_ARB_texture_non_power_of_two" ); + + // Do we have automatic mipmap generation (added to core in version 1.4)? + _glfwWin.has_GL_SGIS_generate_mipmap = + ( _glfwWin.glMajor >= 2 ) || ( _glfwWin.glMinor >= 4 ) || + glfwExtensionSupported( "GL_SGIS_generate_mipmap" ); + + if( _glfwWin.glMajor > 2 ) + { + _glfwWin.GetStringi = (PFNGLGETSTRINGIPROC) glfwGetProcAddress( "glGetStringi" ); + if( !_glfwWin.GetStringi ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + } + + // If full-screen mode was requested, disable mouse cursor + if( mode == GLFW_FULLSCREEN ) + { + glfwDisable( GLFW_MOUSE_CURSOR ); + } + + // Start by clearing the front buffer to black (avoid ugly desktop + // remains in our OpenGL window) + glClear( GL_COLOR_BUFFER_BIT ); + _glfwPlatformSwapBuffers(); + + return GL_TRUE; +} + + +//======================================================================== +// Set hints for opening the window +//======================================================================== + +GLFWAPI void glfwOpenWindowHint( int target, int hint ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return; + } + + switch( target ) + { + case GLFW_REFRESH_RATE: + _glfwLibrary.hints.refreshRate = hint; + break; + case GLFW_ACCUM_RED_BITS: + _glfwLibrary.hints.accumRedBits = hint; + break; + case GLFW_ACCUM_GREEN_BITS: + _glfwLibrary.hints.accumGreenBits = hint; + break; + case GLFW_ACCUM_BLUE_BITS: + _glfwLibrary.hints.accumBlueBits = hint; + break; + case GLFW_ACCUM_ALPHA_BITS: + _glfwLibrary.hints.accumAlphaBits = hint; + break; + case GLFW_AUX_BUFFERS: + _glfwLibrary.hints.auxBuffers = hint; + break; + case GLFW_STEREO: + _glfwLibrary.hints.stereo = hint; + break; + case GLFW_WINDOW_NO_RESIZE: + _glfwLibrary.hints.windowNoResize = hint; + break; + case GLFW_FSAA_SAMPLES: + _glfwLibrary.hints.samples = hint; + break; + case GLFW_OPENGL_VERSION_MAJOR: + _glfwLibrary.hints.glMajor = hint; + break; + case GLFW_OPENGL_VERSION_MINOR: + _glfwLibrary.hints.glMinor = hint; + break; + case GLFW_OPENGL_FORWARD_COMPAT: + _glfwLibrary.hints.glForward = hint; + break; + case GLFW_OPENGL_DEBUG_CONTEXT: + _glfwLibrary.hints.glDebug = hint; + break; + case GLFW_OPENGL_PROFILE: + _glfwLibrary.hints.glProfile = hint; + break; + default: + break; + } +} + + +//======================================================================== +// Properly kill the window / video display +//======================================================================== + +GLFWAPI void glfwCloseWindow( void ) +{ + if( !_glfwInitialized ) + { + return; + } + + // Show mouse pointer again (if hidden) + glfwEnable( GLFW_MOUSE_CURSOR ); + + _glfwPlatformCloseWindow(); + + memset( &_glfwWin, 0, sizeof(_glfwWin) ); + _glfwWin.opened = GL_FALSE; +} + + +//======================================================================== +// glfwSetWindowTitle() - Set the window title +//======================================================================== + +GLFWAPI void glfwSetWindowTitle( const char *title ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + // Set window title + _glfwPlatformSetWindowTitle( title ); +} + + +//======================================================================== +// glfwGetWindowSize() - Get the window size +//======================================================================== + +GLFWAPI void glfwGetWindowSize( int *width, int *height ) +{ + if( width != NULL ) + { + *width = _glfwWin.width; + } + if( height != NULL ) + { + *height = _glfwWin.height; + } +} + + +//======================================================================== +// glfwSetWindowSize() - Set the window size +//======================================================================== + +GLFWAPI void glfwSetWindowSize( int width, int height ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened || _glfwWin.iconified ) + { + return; + } + + // Don't do anything if the window size did not change + if( width == _glfwWin.width && height == _glfwWin.height ) + { + return; + } + + // Change window size + _glfwPlatformSetWindowSize( width, height ); + + // Refresh window parameters (may have changed due to changed video + // modes) + _glfwPlatformRefreshWindowParams(); +} + + +//======================================================================== +// glfwSetWindowPos() - Set the window position +//======================================================================== + +GLFWAPI void glfwSetWindowPos( int x, int y ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened || _glfwWin.fullscreen || + _glfwWin.iconified ) + { + return; + } + + // Set window position + _glfwPlatformSetWindowPos( x, y ); +} + + +//======================================================================== +// glfwIconfyWindow() - Window iconification +//======================================================================== + +GLFWAPI void glfwIconifyWindow( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened || _glfwWin.iconified ) + { + return; + } + + // Iconify window + _glfwPlatformIconifyWindow(); +} + + +//======================================================================== +// glfwRestoreWindow() - Window un-iconification +//======================================================================== + +GLFWAPI void glfwRestoreWindow( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened || !_glfwWin.iconified ) + { + return; + } + + // Restore iconified window + _glfwPlatformRestoreWindow(); + + // Refresh window parameters + _glfwPlatformRefreshWindowParams(); +} + + +//======================================================================== +// Swap buffers (double-buffering) and poll any new events +//======================================================================== + +GLFWAPI void glfwSwapBuffers( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + // Update display-buffer + if( _glfwWin.opened ) + { + _glfwPlatformSwapBuffers(); + } + + // Check for window messages + if( _glfwWin.autoPollEvents ) + { + glfwPollEvents(); + } +} + + +//======================================================================== +// glfwSwapInterval() - Set double buffering swap interval (0 = vsync off) +//======================================================================== + +GLFWAPI void glfwSwapInterval( int interval ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + // Set double buffering swap interval + _glfwPlatformSwapInterval( interval ); +} + + +//======================================================================== +// glfwGetWindowParam() - Get window parameter +//======================================================================== + +GLFWAPI int glfwGetWindowParam( int param ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return 0; + } + + // Is the window opened? + if( !_glfwWin.opened ) + { + if( param == GLFW_OPENED ) + { + return GL_FALSE; + } + return 0; + } + + // Window parameters + switch( param ) + { + case GLFW_OPENED: + return GL_TRUE; + case GLFW_ACTIVE: + return _glfwWin.active; + case GLFW_ICONIFIED: + return _glfwWin.iconified; + case GLFW_ACCELERATED: + return _glfwWin.accelerated; + case GLFW_RED_BITS: + return _glfwWin.redBits; + case GLFW_GREEN_BITS: + return _glfwWin.greenBits; + case GLFW_BLUE_BITS: + return _glfwWin.blueBits; + case GLFW_ALPHA_BITS: + return _glfwWin.alphaBits; + case GLFW_DEPTH_BITS: + return _glfwWin.depthBits; + case GLFW_STENCIL_BITS: + return _glfwWin.stencilBits; + case GLFW_ACCUM_RED_BITS: + return _glfwWin.accumRedBits; + case GLFW_ACCUM_GREEN_BITS: + return _glfwWin.accumGreenBits; + case GLFW_ACCUM_BLUE_BITS: + return _glfwWin.accumBlueBits; + case GLFW_ACCUM_ALPHA_BITS: + return _glfwWin.accumAlphaBits; + case GLFW_AUX_BUFFERS: + return _glfwWin.auxBuffers; + case GLFW_STEREO: + return _glfwWin.stereo; + case GLFW_REFRESH_RATE: + return _glfwWin.refreshRate; + case GLFW_WINDOW_NO_RESIZE: + return _glfwWin.windowNoResize; + case GLFW_FSAA_SAMPLES: + return _glfwWin.samples; + case GLFW_OPENGL_VERSION_MAJOR: + return _glfwWin.glMajor; + case GLFW_OPENGL_VERSION_MINOR: + return _glfwWin.glMinor; + case GLFW_OPENGL_FORWARD_COMPAT: + return _glfwWin.glForward; + case GLFW_OPENGL_DEBUG_CONTEXT: + return _glfwWin.glDebug; + case GLFW_OPENGL_PROFILE: + return _glfwWin.glProfile; + default: + return 0; + } +} + + +//======================================================================== +// glfwSetWindowSizeCallback() - Set callback function for window size +// changes +//======================================================================== + +GLFWAPI void glfwSetWindowSizeCallback( GLFWwindowsizefun cbfun ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + // Set callback function + _glfwWin.windowSizeCallback = cbfun; + + // Call the callback function to let the application know the current + // window size + if( cbfun ) + { + cbfun( _glfwWin.width, _glfwWin.height ); + } +} + +//======================================================================== +// glfwSetWindowCloseCallback() - Set callback function for window close +// events +//======================================================================== + +GLFWAPI void glfwSetWindowCloseCallback( GLFWwindowclosefun cbfun ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + // Set callback function + _glfwWin.windowCloseCallback = cbfun; +} + + +//======================================================================== +// glfwSetWindowRefreshCallback() - Set callback function for window +// refresh events +//======================================================================== + +GLFWAPI void glfwSetWindowRefreshCallback( GLFWwindowrefreshfun cbfun ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + // Set callback function + _glfwWin.windowRefreshCallback = cbfun; +} + + +//======================================================================== +// glfwPollEvents() - Poll for new window and input events +//======================================================================== + +GLFWAPI void glfwPollEvents( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + // Poll for new events + _glfwPlatformPollEvents(); +} + + +//======================================================================== +// glfwWaitEvents() - Wait for new window and input events +//======================================================================== + +GLFWAPI void glfwWaitEvents( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.opened ) + { + return; + } + + // Poll for new events + _glfwPlatformWaitEvents(); +} + diff --git a/lib/x11/CMakeLists.txt b/lib/x11/CMakeLists.txt new file mode 100644 index 00000000..fde2d773 --- /dev/null +++ b/lib/x11/CMakeLists.txt @@ -0,0 +1,36 @@ +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/x11_config.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/x11_config.h @ONLY) + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/libglfw.pc.cmake + ${CMAKE_CURRENT_BINARY_DIR}/libglfw.pc @ONLY) + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${GLFW_INCLUDE_DIR}) + +set(libglfw_SOURCES + ${common_SOURCES} + x11_enable.c + x11_fullscreen.c + x11_glext.c + x11_init.c + x11_joystick.c + x11_keysym2unicode.c + x11_time.c + x11_window.c) + +add_library(libglfwStatic STATIC ${libglfw_SOURCES}) +add_library(libglfwShared SHARED ${libglfw_SOURCES}) +target_link_libraries(libglfwShared ${GLFW_LIBRARIES}) +set_target_properties(libglfwStatic libglfwShared PROPERTIES + CLEAN_DIRECT_OUTPUT 1 + OUTPUT_NAME glfw +) + +install(TARGETS libglfwStatic libglfwShared DESTINATION lib) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libglfw.pc DESTINATION lib/pkgconfig) + diff --git a/lib/x11/libglfw.pc.cmake b/lib/x11/libglfw.pc.cmake new file mode 100644 index 00000000..adc455f8 --- /dev/null +++ b/lib/x11/libglfw.pc.cmake @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: GLFW +Description: A portable framework for OpenGL development +Version: 2.7 +URL: http://glfw.sourceforge.net/ +Libs: -L${libdir} -lglfw @GLFW_LIBRARIES@ +Cflags: -I${includedir} diff --git a/lib/x11/platform.h b/lib/x11/platform.h new file mode 100644 index 00000000..831f16f1 --- /dev/null +++ b/lib/x11/platform.h @@ -0,0 +1,433 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: X11/GLX +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#ifndef _platform_h_ +#define _platform_h_ + + +// This is the X11 version of GLFW +#define _GLFW_X11 + + +// Include files +#include +#include +#include +#include +#include +#include +#include + +#include "../../include/GL/glfw.h" +#include "x11_config.h" + +// We need declarations for GLX version 1.3 or above even if the server doesn't +// support version 1.3 +#ifndef GLX_VERSION_1_3 + #error "GLX header version 1.3 or above is required" +#endif + +#if defined( _GLFW_HAS_XF86VIDMODE ) && defined( _GLFW_HAS_XRANDR ) + #error "Xf86VidMode and RandR extensions cannot both be enabled" +#endif + +// With XFree86, we can use the XF86VidMode extension +#if defined( _GLFW_HAS_XF86VIDMODE ) + #include +#endif + +#if defined( _GLFW_HAS_XRANDR ) + #include +#endif + +// Do we have support for dlopen/dlsym? +#if defined( _GLFW_HAS_DLOPEN ) + #include +#endif + +// We support two different ways for getting the number of processors in +// the system: sysconf (POSIX) and sysctl (BSD?) +#if defined( _GLFW_HAS_SYSCONF ) + + // Use a single constant for querying number of online processors using + // the sysconf function (e.g. SGI defines _SC_NPROC_ONLN instead of + // _SC_NPROCESSORS_ONLN) + #ifndef _SC_NPROCESSORS_ONLN + #ifdef _SC_NPROC_ONLN + #define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN + #else + #error POSIX constant _SC_NPROCESSORS_ONLN not defined! + #endif + #endif + + // Macro for querying the number of processors + #define _glfw_numprocessors(n) n=(int)sysconf(_SC_NPROCESSORS_ONLN) + +#elif defined( _GLFW_HAS_SYSCTL ) + + #include + #include + + // Macro for querying the number of processors + #define _glfw_numprocessors(n) { \ + int mib[2], ncpu; \ + size_t len = 1; \ + mib[0] = CTL_HW; \ + mib[1] = HW_NCPU; \ + n = 1; \ + if( sysctl( mib, 2, &ncpu, &len, NULL, 0 ) != -1 ) \ + { \ + if( len > 0 ) \ + { \ + n = ncpu; \ + } \ + } \ + } + +#else + + // If neither sysconf nor sysctl is supported, assume single processor + // system + #define _glfw_numprocessors(n) n=1 + +#endif + +// Pointer length integer +// One day, this will most likely move into glfw.h +typedef intptr_t GLFWintptr; + + +#ifndef GLX_SGI_swap_control + +// Function signature for GLX_SGI_swap_control +typedef int ( * PFNGLXSWAPINTERVALSGIPROC) (int interval); + +#endif /*GLX_SGI_swap_control*/ + + +#ifndef GLX_SGIX_fbconfig + +/* Type definitions for GLX_SGIX_fbconfig */ +typedef XID GLXFBConfigIDSGIX; +typedef struct __GLXFBConfigRec *GLXFBConfigSGIX; + +/* Function signatures for GLX_SGIX_fbconfig */ +typedef int ( * PFNGLXGETFBCONFIGATTRIBSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value); +typedef GLXFBConfigSGIX * ( * PFNGLXCHOOSEFBCONFIGSGIXPROC) (Display *dpy, int screen, int *attrib_list, int *nelements); +typedef GLXContext ( * PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct); +typedef XVisualInfo * ( * PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config); + +/* Tokens for GLX_SGIX_fbconfig */ +#define GLX_WINDOW_BIT_SGIX 0x00000001 +#define GLX_PIXMAP_BIT_SGIX 0x00000002 +#define GLX_RGBA_BIT_SGIX 0x00000001 +#define GLX_COLOR_INDEX_BIT_SGIX 0x00000002 +#define GLX_DRAWABLE_TYPE_SGIX 0x8010 +#define GLX_RENDER_TYPE_SGIX 0x8011 +#define GLX_X_RENDERABLE_SGIX 0x8012 +#define GLX_FBCONFIG_ID_SGIX 0x8013 +#define GLX_RGBA_TYPE_SGIX 0x8014 +#define GLX_COLOR_INDEX_TYPE_SGIX 0x8015 +#define GLX_SCREEN_EXT 0x800C + +#endif /*GLX_SGIX_fbconfig*/ + + +#ifndef GLX_ARB_create_context + +/* Tokens for glXCreateContextAttribsARB attributes */ +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define GLX_CONTEXT_FLAGS_ARB 0x2094 + +/* Bits for WGL_CONTEXT_FLAGS_ARB */ +#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 + +/* Prototype for glXCreateContextAttribs */ +typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)( Display *display, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); + +#endif /*GLX_ARB_create_context*/ + + +#ifndef GLX_ARB_create_context_profile + +/* Tokens for glXCreateContextAttribsARB attributes */ +#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 + +/* BIts for GLX_CONTEXT_PROFILE_MASK_ARB */ +#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 + +#endif /*GLX_ARB_create_context_profile*/ + + +#ifndef GL_VERSION_3_0 + +typedef const GLubyte * (APIENTRY *PFNGLGETSTRINGIPROC) (GLenum, GLuint); + +#endif /*GL_VERSION_3_0*/ + + + +//======================================================================== +// Global variables (GLFW internals) +//======================================================================== + +//------------------------------------------------------------------------ +// Window structure +//------------------------------------------------------------------------ +typedef struct _GLFWwin_struct _GLFWwin; + +struct _GLFWwin_struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // User callback functions + GLFWwindowsizefun windowSizeCallback; + GLFWwindowclosefun windowCloseCallback; + GLFWwindowrefreshfun windowRefreshCallback; + GLFWmousebuttonfun mouseButtonCallback; + GLFWmouseposfun mousePosCallback; + GLFWmousewheelfun mouseWheelCallback; + GLFWkeyfun keyCallback; + GLFWcharfun charCallback; + + // User selected window settings + int fullscreen; // Fullscreen flag + int mouseLock; // Mouse-lock flag + int autoPollEvents; // Auto polling flag + int sysKeysDisabled; // System keys disabled flag + int windowNoResize; // Resize- and maximize gadgets disabled flag + int refreshRate; // Vertical monitor refresh rate + + // Window status & parameters + int opened; // Flag telling if window is opened or not + int active; // Application active flag + int iconified; // Window iconified flag + int width, height; // Window width and heigth + int accelerated; // GL_TRUE if window is HW accelerated + + // Framebuffer attributes + int redBits; + int greenBits; + int blueBits; + int alphaBits; + int depthBits; + int stencilBits; + int accumRedBits; + int accumGreenBits; + int accumBlueBits; + int accumAlphaBits; + int auxBuffers; + int stereo; + int samples; + + // OpenGL extensions and context attributes + int has_GL_SGIS_generate_mipmap; + int has_GL_ARB_texture_non_power_of_two; + int glMajor, glMinor, glRevision; + int glForward, glDebug, glProfile; + + PFNGLGETSTRINGIPROC GetStringi; + + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Platform specific window resources + Colormap colormap; // Window colormap + Window window; // Window + Window root; // Root window for screen + int screen; // Screen ID + XVisualInfo *visual; // Visual for selected GLXFBConfig + GLXFBConfigID fbconfigID; // ID of selected GLXFBConfig + GLXContext context; // OpenGL rendering context + Atom wmDeleteWindow; // WM_DELETE_WINDOW atom + Atom wmPing; // _NET_WM_PING atom + Atom wmState; // _NET_WM_STATE atom + Atom wmStateFullscreen; // _NET_WM_STATE_FULLSCREEN atom + Atom wmActiveWindow; // _NET_ACTIVE_WINDOW atom + Cursor cursor; // Invisible cursor for hidden cursor + + // GLX extensions + PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI; + PFNGLXGETFBCONFIGATTRIBSGIXPROC GetFBConfigAttribSGIX; + PFNGLXCHOOSEFBCONFIGSGIXPROC ChooseFBConfigSGIX; + PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC CreateContextWithConfigSGIX; + PFNGLXGETVISUALFROMFBCONFIGSGIXPROC GetVisualFromFBConfigSGIX; + PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; + GLboolean has_GLX_SGIX_fbconfig; + GLboolean has_GLX_SGI_swap_control; + GLboolean has_GLX_ARB_multisample; + GLboolean has_GLX_ARB_create_context; + GLboolean has_GLX_ARB_create_context_profile; + + // Various platform specific internal variables + GLboolean hasEWMH; // True if window manager supports EWMH + GLboolean overrideRedirect; // True if window is OverrideRedirect + GLboolean keyboardGrabbed; // True if keyboard is currently grabbed + GLboolean pointerGrabbed; // True if pointer is currently grabbed + GLboolean pointerHidden; // True if pointer is currently hidden + + // Screensaver data + struct { + int changed; + int timeout; + int interval; + int blanking; + int exposure; + } Saver; + + // Fullscreen data + struct { + int modeChanged; +#if defined( _GLFW_HAS_XF86VIDMODE ) + XF86VidModeModeInfo oldMode; +#endif +#if defined( _GLFW_HAS_XRANDR ) + SizeID oldSizeID; + int oldWidth; + int oldHeight; + Rotation oldRotation; +#endif + } FS; +}; + +GLFWGLOBAL _GLFWwin _glfwWin; + + +//------------------------------------------------------------------------ +// User input status (most of this should go in _GLFWwin) +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Mouse status + int MousePosX, MousePosY; + int WheelPos; + char MouseButton[ GLFW_MOUSE_BUTTON_LAST+1 ]; + + // Keyboard status + char Key[ GLFW_KEY_LAST+1 ]; + int LastChar; + + // User selected settings + int StickyKeys; + int StickyMouseButtons; + int KeyRepeat; + + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Platform specific internal variables + int MouseMoved, CursorPosX, CursorPosY; + +} _glfwInput; + + +//------------------------------------------------------------------------ +// Library global data +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Window opening hints + _GLFWhints hints; + +// ========= PLATFORM SPECIFIC PART ====================================== + + Display *display; + + // Server-side GLX version + int glxMajor, glxMinor; + + struct { + int available; + int eventBase; + int errorBase; + } XF86VidMode; + + struct { + int available; + int eventBase; + int errorBase; + } XRandR; + + // Timer data + struct { + double resolution; + long long t0; + } Timer; + +#if defined(_GLFW_DLOPEN_LIBGL) + struct { + void *libGL; // dlopen handle for libGL.so + } Libs; +#endif +} _glfwLibrary; + + +//------------------------------------------------------------------------ +// Joystick information & state +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + int Present; + int fd; + int NumAxes; + int NumButtons; + float *Axis; + unsigned char *Button; +} _glfwJoy[ GLFW_JOYSTICK_LAST + 1 ]; + + +//======================================================================== +// Prototypes for platform specific internal functions +//======================================================================== + +// Time +void _glfwInitTimer( void ); + +// Fullscreen support +int _glfwGetClosestVideoMode( int screen, int *width, int *height, int *rate ); +void _glfwSetVideoModeMODE( int screen, int mode, int rate ); +void _glfwSetVideoMode( int screen, int *width, int *height, int *rate ); +void _glfwRestoreVideoMode( void ); + +// Joystick input +void _glfwInitJoysticks( void ); +void _glfwTerminateJoysticks( void ); + +// Unicode support +long _glfwKeySym2Unicode( KeySym keysym ); + + +#endif // _platform_h_ diff --git a/lib/x11/x11_config.h.cmake b/lib/x11/x11_config.h.cmake new file mode 100644 index 00000000..d578d574 --- /dev/null +++ b/lib/x11/x11_config.h.cmake @@ -0,0 +1,14 @@ +/* Configure build time options of GLFW */ + +/* Define this to 1 if XRandR is available */ +#cmakedefine _GLFW_HAS_XRANDR 1 +/* Define this to 1 if Xf86VidMode is available */ +#cmakedefine _GLFW_HAS_XF86VIDMODE 1 + +/* Define this to 1 if glXGetProcAddress is available */ +#cmakedefine _GLFW_HAS_GLXGETPROCADDRESS 1 +/* Define this to 1 if glXGetProcAddressARB is available */ +#cmakedefine _GLFW_HAS_GLXGETPROCADDRESSARB 1 +/* Define this to 1 if glXGetProcAddressEXT is available */ +#cmakedefine _GLFW_HAS_GLXGETPROCADDRESSEXT 1 + diff --git a/lib/x11/x11_enable.c b/lib/x11/x11_enable.c new file mode 100644 index 00000000..88308d5a --- /dev/null +++ b/lib/x11/x11_enable.c @@ -0,0 +1,64 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: X11 (Unix) +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Enable system keys +//======================================================================== + +void _glfwPlatformEnableSystemKeys( void ) +{ + if( _glfwWin.keyboardGrabbed ) + { + XUngrabKeyboard( _glfwLibrary.display, CurrentTime ); + _glfwWin.keyboardGrabbed = GL_FALSE; + } +} + +//======================================================================== +// Disable system keys +//======================================================================== + +void _glfwPlatformDisableSystemKeys( void ) +{ + if( XGrabKeyboard( _glfwLibrary.display, _glfwWin.window, True, + GrabModeAsync, GrabModeAsync, CurrentTime ) == + GrabSuccess ) + { + _glfwWin.keyboardGrabbed = GL_TRUE; + } +} + diff --git a/lib/x11/x11_fullscreen.c b/lib/x11/x11_fullscreen.c new file mode 100644 index 00000000..f720214b --- /dev/null +++ b/lib/x11/x11_fullscreen.c @@ -0,0 +1,572 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: X11/GLX +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// Convert BPP to RGB bits (based on "best guess") +//======================================================================== + +static void BPP2RGB( int bpp, int *r, int *g, int *b ) +{ + int delta; + + // Special case: BPP = 32 (I don't think this is necessary for X11??) + if( bpp == 32 ) + bpp = 24; + + // Convert "bits per pixel" to red, green & blue sizes + *r = *g = *b = bpp / 3; + delta = bpp - (*r * 3); + if( delta >= 1 ) + { + *g = *g + 1; + } + if( delta == 2 ) + { + *r = *r + 1; + } +} + + +//======================================================================== +// Finds the video mode closest in size to the specified desired size +//======================================================================== + +int _glfwGetClosestVideoMode( int screen, int *width, int *height, int *rate ) +{ +#if defined( _GLFW_HAS_XRANDR ) + int i, match, bestmatch; + int sizecount, bestsize; + int ratecount, bestrate; + short *ratelist; + XRRScreenConfiguration *sc; + XRRScreenSize *sizelist; + + if( _glfwLibrary.XRandR.available ) + { + sc = XRRGetScreenInfo( _glfwLibrary.display, + RootWindow( _glfwLibrary.display, screen ) ); + + sizelist = XRRConfigSizes( sc, &sizecount ); + + // Find the best matching mode + bestsize = -1; + bestmatch = INT_MAX; + for( i = 0; i < sizecount; i++ ) + { + match = (*width - sizelist[i].width) * + (*width - sizelist[i].width) + + (*height - sizelist[i].height) * + (*height - sizelist[i].height); + if( match < bestmatch ) + { + bestmatch = match; + bestsize = i; + } + } + + if( bestsize != -1 ) + { + // Report width & height of best matching mode + *width = sizelist[bestsize].width; + *height = sizelist[bestsize].height; + + if( *rate > 0 ) + { + ratelist = XRRConfigRates( sc, bestsize, &ratecount ); + + bestrate = -1; + bestmatch = INT_MAX; + for( i = 0; i < ratecount; i++ ) + { + match = abs( ratelist[i] - *rate ); + if( match < bestmatch ) + { + bestmatch = match; + bestrate = ratelist[i]; + } + } + + if( bestrate != -1 ) + { + *rate = bestrate; + } + } + } + + // Free modelist + XRRFreeScreenConfigInfo( sc ); + + if( bestsize != -1 ) + { + return bestsize; + } + } +#elif defined( _GLFW_HAS_XF86VIDMODE ) + XF86VidModeModeInfo **modelist; + int modecount, i, bestmode, bestmatch, match; + + // Use the XF86VidMode extension to control video resolution + if( _glfwLibrary.XF86VidMode.available ) + { + // Get a list of all available display modes + XF86VidModeGetAllModeLines( _glfwLibrary.display, screen, + &modecount, &modelist ); + + // Find the best matching mode + bestmode = -1; + bestmatch = INT_MAX; + for( i = 0; i < modecount; i++ ) + { + match = (*width - modelist[i]->hdisplay) * + (*width - modelist[i]->hdisplay) + + (*height - modelist[i]->vdisplay) * + (*height - modelist[i]->vdisplay); + if( match < bestmatch ) + { + bestmatch = match; + bestmode = i; + } + } + + if( bestmode != -1 ) + { + // Report width & height of best matching mode + *width = modelist[ bestmode ]->hdisplay; + *height = modelist[ bestmode ]->vdisplay; + } + + // Free modelist + XFree( modelist ); + + if( bestmode != -1 ) + { + return bestmode; + } + } +#endif + + // Default: Simply use the screen resolution + *width = DisplayWidth( _glfwLibrary.display, screen ); + *height = DisplayHeight( _glfwLibrary.display, screen ); + + return 0; +} + + +//======================================================================== +// Change the current video mode +//======================================================================== + +void _glfwSetVideoModeMODE( int screen, int mode, int rate ) +{ +#if defined( _GLFW_HAS_XRANDR ) + XRRScreenConfiguration *sc; + Window root; + + if( _glfwLibrary.XRandR.available ) + { + root = RootWindow( _glfwLibrary.display, screen ); + sc = XRRGetScreenInfo( _glfwLibrary.display, root ); + + // Remember old size and flag that we have changed the mode + if( !_glfwWin.FS.modeChanged ) + { + _glfwWin.FS.oldSizeID = XRRConfigCurrentConfiguration( sc, &_glfwWin.FS.oldRotation ); + _glfwWin.FS.oldWidth = DisplayWidth( _glfwLibrary.display, screen ); + _glfwWin.FS.oldHeight = DisplayHeight( _glfwLibrary.display, screen ); + + _glfwWin.FS.modeChanged = GL_TRUE; + } + + if( rate > 0 ) + { + // Set desired configuration + XRRSetScreenConfigAndRate( _glfwLibrary.display, + sc, + root, + mode, + RR_Rotate_0, + (short) rate, + CurrentTime ); + } + else + { + // Set desired configuration + XRRSetScreenConfig( _glfwLibrary.display, + sc, + root, + mode, + RR_Rotate_0, + CurrentTime ); + } + + XRRFreeScreenConfigInfo( sc ); + } +#elif defined( _GLFW_HAS_XF86VIDMODE ) + XF86VidModeModeInfo **modelist; + int modecount; + + // Use the XF86VidMode extension to control video resolution + if( _glfwLibrary.XF86VidMode.available ) + { + // Get a list of all available display modes + XF86VidModeGetAllModeLines( _glfwLibrary.display, screen, + &modecount, &modelist ); + + // Unlock mode switch if necessary + if( _glfwWin.FS.modeChanged ) + { + XF86VidModeLockModeSwitch( _glfwLibrary.display, screen, 0 ); + } + + // Change the video mode to the desired mode + XF86VidModeSwitchToMode( _glfwLibrary.display, screen, + modelist[ mode ] ); + + // Set viewport to upper left corner (where our window will be) + XF86VidModeSetViewPort( _glfwLibrary.display, screen, 0, 0 ); + + // Lock mode switch + XF86VidModeLockModeSwitch( _glfwLibrary.display, screen, 1 ); + + // Remember old mode and flag that we have changed the mode + if( !_glfwWin.FS.modeChanged ) + { + _glfwWin.FS.oldMode = *modelist[ 0 ]; + _glfwWin.FS.modeChanged = GL_TRUE; + } + + // Free mode list + XFree( modelist ); + } +#endif +} + + +//======================================================================== +// Change the current video mode +//======================================================================== + +void _glfwSetVideoMode( int screen, int *width, int *height, int *rate ) +{ + int bestmode; + + // Find a best match mode + bestmode = _glfwGetClosestVideoMode( screen, width, height, rate ); + + // Change mode + _glfwSetVideoModeMODE( screen, bestmode, *rate ); +} + + +//======================================================================== +// Restore the previously saved (original) video mode +//======================================================================== + +void _glfwRestoreVideoMode( void ) +{ + if( _glfwWin.FS.modeChanged ) + { +#if defined( _GLFW_HAS_XRANDR ) + if( _glfwLibrary.XRandR.available ) + { + XRRScreenConfiguration *sc; + + if( _glfwLibrary.XRandR.available ) + { + sc = XRRGetScreenInfo( _glfwLibrary.display, _glfwWin.root ); + + XRRSetScreenConfig( _glfwLibrary.display, + sc, + _glfwWin.root, + _glfwWin.FS.oldSizeID, + _glfwWin.FS.oldRotation, + CurrentTime ); + + XRRFreeScreenConfigInfo( sc ); + } + } +#elif defined( _GLFW_HAS_XF86VIDMODE ) + if( _glfwLibrary.XF86VidMode.available ) + { + // Unlock mode switch + XF86VidModeLockModeSwitch( _glfwLibrary.display, _glfwWin.screen, 0 ); + + // Change the video mode back to the old mode + XF86VidModeSwitchToMode( _glfwLibrary.display, + _glfwWin.screen, + &_glfwWin.FS.oldMode ); + } +#endif + _glfwWin.FS.modeChanged = GL_FALSE; + } +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +struct _glfwResolution +{ + int width; + int height; +}; + +//======================================================================== +// List available video modes +//======================================================================== + +int _glfwPlatformGetVideoModes( GLFWvidmode *list, int maxcount ) +{ + int count, k, l, r, g, b, rgba, gl; + int depth, screen; + Display *dpy; + XVisualInfo *vislist, dummy; + int viscount, rgbcount, rescount; + int *rgbarray; + struct _glfwResolution *resarray; +#if defined( _GLFW_HAS_XRANDR ) + XRRScreenConfiguration *sc; + XRRScreenSize *sizelist; + int sizecount; +#elif defined( _GLFW_HAS_XF86VIDMODE ) + XF86VidModeModeInfo **modelist; + int modecount, width, height; +#endif + + // Get display and screen + dpy = _glfwLibrary.display; + screen = DefaultScreen( dpy ); + + // Get list of visuals + vislist = XGetVisualInfo( dpy, 0, &dummy, &viscount ); + if( vislist == NULL ) + { + return 0; + } + + rgbarray = (int*) malloc( sizeof(int) * viscount ); + rgbcount = 0; + + // Build RGB array + for( k = 0; k < viscount; k++ ) + { + // Does the visual support OpenGL & true color? + glXGetConfig( dpy, &vislist[k], GLX_USE_GL, &gl ); + glXGetConfig( dpy, &vislist[k], GLX_RGBA, &rgba ); + if( gl && rgba ) + { + // Get color depth for this visual + depth = vislist[k].depth; + + // Convert to RGB + BPP2RGB( depth, &r, &g, &b ); + depth = (r<<16) | (g<<8) | b; + + // Is this mode unique? + for( l = 0; l < rgbcount; l++ ) + { + if( depth == rgbarray[ l ] ) + { + break; + } + } + if( l >= rgbcount ) + { + rgbarray[ rgbcount ] = depth; + rgbcount++; + } + } + } + + rescount = 0; + resarray = NULL; + + // Build resolution array +#if defined( _GLFW_HAS_XRANDR ) + if( _glfwLibrary.XRandR.available ) + { + sc = XRRGetScreenInfo( dpy, RootWindow( dpy, screen ) ); + sizelist = XRRConfigSizes( sc, &sizecount ); + + resarray = (struct _glfwResolution*) malloc( sizeof(struct _glfwResolution) * sizecount ); + + for( k = 0; k < sizecount; k++ ) + { + resarray[ rescount ].width = sizelist[ k ].width; + resarray[ rescount ].height = sizelist[ k ].height; + rescount++; + } + + XRRFreeScreenConfigInfo( sc ); + } +#elif defined( _GLFW_HAS_XF86VIDMODE ) + if( _glfwLibrary.XF86VidMode.available ) + { + XF86VidModeGetAllModeLines( dpy, screen, &modecount, &modelist ); + + resarray = (struct _glfwResolution*) malloc( sizeof(struct _glfwResolution) * modecount ); + + for( k = 0; k < modecount; k++ ) + { + width = modelist[ k ]->hdisplay; + height = modelist[ k ]->vdisplay; + + // Is this mode unique? + for( l = 0; l < rescount; l++ ) + { + if( width == resarray[ l ].width && height == resarray[ l ].height ) + { + break; + } + } + + if( l >= rescount ) + { + resarray[ rescount ].width = width; + resarray[ rescount ].height = height; + rescount++; + } + } + + XFree( modelist ); + } +#endif + + if( !resarray ) + { + rescount = 1; + resarray = (struct _glfwResolution*) malloc( sizeof(struct _glfwResolution) * rescount ); + + resarray[ 0 ].width = DisplayWidth( dpy, screen ); + resarray[ 0 ].height = DisplayHeight( dpy, screen ); + } + + // Build permutations of colors and resolutions + count = 0; + for( k = 0; k < rgbcount && count < maxcount; k++ ) + { + for( l = 0; l < rescount && count < maxcount; l++ ) + { + list[count].Width = resarray[ l ].width; + list[count].Height = resarray[ l ].height; + list[count].RedBits = (rgbarray[ k ] >> 16) & 255; + list[count].GreenBits = (rgbarray[ k ] >> 8) & 255; + list[count].BlueBits = rgbarray[ k ] & 255; + count++; + } + } + + // Free visuals list + XFree( vislist ); + + free( resarray ); + free( rgbarray ); + + return count; +} + + +//======================================================================== +// Get the desktop video mode +//======================================================================== + +void _glfwPlatformGetDesktopMode( GLFWvidmode *mode ) +{ + Display *dpy; + int bpp, screen; +#if defined( _GLFW_HAS_XF86VIDMODE ) + XF86VidModeModeInfo **modelist; + int modecount; +#endif + + // Get display and screen + dpy = _glfwLibrary.display; + screen = DefaultScreen( dpy ); + + // Get display depth + bpp = DefaultDepth( dpy, screen ); + + // Convert BPP to RGB bits + BPP2RGB( bpp, &mode->RedBits, &mode->GreenBits, &mode->BlueBits ); + +#if defined( _GLFW_HAS_XRANDR ) + if( _glfwLibrary.XRandR.available ) + { + if( _glfwWin.FS.modeChanged ) + { + mode->Width = _glfwWin.FS.oldWidth; + mode->Height = _glfwWin.FS.oldHeight; + return; + } + } +#elif defined( _GLFW_HAS_XF86VIDMODE ) + if( _glfwLibrary.XF86VidMode.available ) + { + if( _glfwWin.FS.modeChanged ) + { + // The old (desktop) mode is stored in _glfwWin.FS.oldMode + mode->Width = _glfwWin.FS.oldMode.hdisplay; + mode->Height = _glfwWin.FS.oldMode.vdisplay; + } + else + { + // Use the XF86VidMode extension to get list of video modes + XF86VidModeGetAllModeLines( dpy, screen, &modecount, + &modelist ); + + // The first mode in the list is the current (desktio) mode + mode->Width = modelist[ 0 ]->hdisplay; + mode->Height = modelist[ 0 ]->vdisplay; + + // Free list + XFree( modelist ); + } + + return; + } +#endif + + // Get current display width and height + mode->Width = DisplayWidth( dpy, screen ); + mode->Height = DisplayHeight( dpy, screen ); +} + diff --git a/lib/x11/x11_glext.c b/lib/x11/x11_glext.c new file mode 100644 index 00000000..bf77dcfa --- /dev/null +++ b/lib/x11/x11_glext.c @@ -0,0 +1,90 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: X11/GLX +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +void (*glXGetProcAddress(const GLubyte *procName))(); +void (*glXGetProcAddressARB(const GLubyte *procName))(); +void (*glXGetProcAddressEXT(const GLubyte *procName))(); + +// We support four different ways for getting addresses for GL/GLX +// extension functions: glXGetProcAddress, glXGetProcAddressARB, +// glXGetProcAddressEXT, and dlsym +#if defined( _GLFW_HAS_GLXGETPROCADDRESSARB ) + #define _glfw_glXGetProcAddress(x) glXGetProcAddressARB(x) +#elif defined( _GLFW_HAS_GLXGETPROCADDRESS ) + #define _glfw_glXGetProcAddress(x) glXGetProcAddress(x) +#elif defined( _GLFW_HAS_GLXGETPROCADDRESSEXT ) + #define _glfw_glXGetProcAddress(x) glXGetProcAddressEXT(x) +#elif defined( _GLFW_HAS_DLOPEN ) + #define _glfw_glXGetProcAddress(x) dlsym(_glfwLibs.libGL,x) + #define _GLFW_DLOPEN_LIBGL +#else +#define _glfw_glXGetProcAddress(x) NULL +#endif + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Check if an OpenGL extension is available at runtime +//======================================================================== + +int _glfwPlatformExtensionSupported( const char *extension ) +{ + const GLubyte *extensions; + + // Get list of GLX extensions + extensions = (const GLubyte*) glXQueryExtensionsString( _glfwLibrary.display, + _glfwWin.screen ); + if( extensions != NULL ) + { + if( _glfwStringInExtensionString( extension, extensions ) ) + { + return GL_TRUE; + } + } + + return GL_FALSE; +} + + +//======================================================================== +// Get the function pointer to an OpenGL function +//======================================================================== + +void * _glfwPlatformGetProcAddress( const char *procname ) +{ + return (void *) _glfw_glXGetProcAddress( (const GLubyte *) procname ); +} + diff --git a/lib/x11/x11_init.c b/lib/x11/x11_init.c new file mode 100644 index 00000000..612a524f --- /dev/null +++ b/lib/x11/x11_init.c @@ -0,0 +1,206 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: X11/GLX +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// Dynamically load libraries +//======================================================================== + +static void initLibraries( void ) +{ +#ifdef _GLFW_DLOPEN_LIBGL + int i; + char *libGL_names[ ] = + { + "libGL.so", + "libGL.so.1", + "/usr/lib/libGL.so", + "/usr/lib/libGL.so.1", + NULL + }; + + _glfwLibrary.Libs.libGL = NULL; + for( i = 0; !libGL_names[ i ] != NULL; i ++ ) + { + _glfwLibrary.Libs.libGL = dlopen( libGL_names[ i ], + RTLD_LAZY | RTLD_GLOBAL ); + if( _glfwLibrary.Libs.libGL ) + break; + } +#endif +} + + +//======================================================================== +// Terminate GLFW when exiting application +//======================================================================== + +static void glfw_atexit( void ) +{ + glfwTerminate(); +} + + +//======================================================================== +// Initialize X11 display +//======================================================================== + +static int initDisplay( void ) +{ + // Open display + _glfwLibrary.display = XOpenDisplay( 0 ); + if( !_glfwLibrary.display ) + { + fprintf(stderr, "Failed to open X display\n"); + return GL_FALSE; + } + + // Check for XF86VidMode extension +#ifdef _GLFW_HAS_XF86VIDMODE + _glfwLibrary.XF86VidMode.available = + XF86VidModeQueryExtension( _glfwLibrary.display, + &_glfwLibrary.XF86VidMode.eventBase, + &_glfwLibrary.XF86VidMode.errorBase); +#else + _glfwLibrary.XF86VidMode.available = 0; +#endif + + // Check for XRandR extension +#ifdef _GLFW_HAS_XRANDR + _glfwLibrary.XRandR.available = + XRRQueryExtension( _glfwLibrary.display, + &_glfwLibrary.XRandR.eventBase, + &_glfwLibrary.XRandR.errorBase ); +#else + _glfwLibrary.XRandR.available = 0; +#endif + + // Fullscreen & screen saver settings + // Check if GLX is supported on this display + if( !glXQueryExtension( _glfwLibrary.display, NULL, NULL ) ) + { + fprintf(stderr, "GLX not supported\n"); + return GL_FALSE; + } + + // Retrieve GLX version + if( !glXQueryVersion( _glfwLibrary.display, + &_glfwLibrary.glxMajor, + &_glfwLibrary.glxMinor ) ) + { + fprintf(stderr, "Unable to query GLX version\n"); + return GL_FALSE; + } + + return GL_TRUE; +} + + +//======================================================================== +// Terminate X11 display +//======================================================================== + +static void terminateDisplay( void ) +{ + // Open display + if( _glfwLibrary.display ) + { + XCloseDisplay( _glfwLibrary.display ); + _glfwLibrary.display = NULL; + } +} + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Initialize various GLFW state +//======================================================================== + +int _glfwPlatformInit( void ) +{ + // Initialize display + if( !initDisplay() ) + { + return GL_FALSE; + } + + // Try to load libGL.so if necessary + initLibraries(); + + // Install atexit() routine + atexit( glfw_atexit ); + + // Initialize joysticks + _glfwInitJoysticks(); + + // Start the timer + _glfwInitTimer(); + + return GL_TRUE; +} + + +//======================================================================== +// Close window and shut down library +//======================================================================== + +int _glfwPlatformTerminate( void ) +{ + // Close OpenGL window + glfwCloseWindow(); + + // Terminate display + terminateDisplay(); + + // Terminate joysticks + _glfwTerminateJoysticks(); + + // Unload libGL.so if necessary +#ifdef _GLFW_DLOPEN_LIBGL + if( _glfwLibrary.Libs.libGL != NULL ) + { + dlclose( _glfwLibrary.Libs.libGL ); + _glfwLibrary.Libs.libGL = NULL; + } +#endif + + return GL_TRUE; +} + diff --git a/lib/x11/x11_joystick.c b/lib/x11/x11_joystick.c new file mode 100644 index 00000000..90c9c648 --- /dev/null +++ b/lib/x11/x11_joystick.c @@ -0,0 +1,367 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: X11/GLX +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +//======================================================================== +// Note: Only Linux joystick input is supported at the moment. Other +// systems will behave as if there are no joysticks connected. +//======================================================================== + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +#ifdef _GLFW_USE_LINUX_JOYSTICKS + +//------------------------------------------------------------------------ +// Here are the Linux joystick driver v1.x interface definitions that we +// use (we do not want to rely on ): +//------------------------------------------------------------------------ + +#include +#include +#include + +// Joystick event types +#define JS_EVENT_BUTTON 0x01 /* button pressed/released */ +#define JS_EVENT_AXIS 0x02 /* joystick moved */ +#define JS_EVENT_INIT 0x80 /* initial state of device */ + +// Joystick event structure +struct js_event { + unsigned int time; /* (u32) event timestamp in milliseconds */ + signed short value; /* (s16) value */ + unsigned char type; /* (u8) event type */ + unsigned char number; /* (u8) axis/button number */ +}; + +// Joystick IOCTL commands +#define JSIOCGVERSION _IOR('j', 0x01, int) /* get driver version (u32) */ +#define JSIOCGAXES _IOR('j', 0x11, char) /* get number of axes (u8) */ +#define JSIOCGBUTTONS _IOR('j', 0x12, char) /* get number of buttons (u8) */ + +#endif // _GLFW_USE_LINUX_JOYSTICKS + + +//======================================================================== +// _glfwInitJoysticks() - Initialize joystick interface +//======================================================================== + +void _glfwInitJoysticks( void ) +{ +#ifdef _GLFW_USE_LINUX_JOYSTICKS + int k, n, fd, joy_count; + char *joy_base_name, joy_dev_name[ 20 ]; + int driver_version = 0x000800; + char ret_data; +#endif // _GLFW_USE_LINUX_JOYSTICKS + int i; + + // Start by saying that there are no sticks + for( i = 0; i <= GLFW_JOYSTICK_LAST; ++ i ) + { + _glfwJoy[ i ].Present = GL_FALSE; + } + +#ifdef _GLFW_USE_LINUX_JOYSTICKS + + // Try to open joysticks (nonblocking) + joy_count = 0; + for( k = 0; k <= 1 && joy_count <= GLFW_JOYSTICK_LAST; ++ k ) + { + // Pick joystick base name + switch( k ) + { + case 0: + joy_base_name = "/dev/input/js"; // USB sticks + break; + case 1: + joy_base_name = "/dev/js"; // "Legacy" sticks + break; + default: + continue; // (should never happen) + } + + // Try to open a few of these sticks + for( i = 0; i <= 50 && joy_count <= GLFW_JOYSTICK_LAST; ++ i ) + { + sprintf( joy_dev_name, "%s%d", joy_base_name, i ); + fd = open( joy_dev_name, O_NONBLOCK ); + if( fd != -1 ) + { + // Remember fd + _glfwJoy[ joy_count ].fd = fd; + + // Check that the joystick driver version is 1.0+ + ioctl( fd, JSIOCGVERSION, &driver_version ); + if( driver_version < 0x010000 ) + { + // It's an old 0.x interface (we don't support it) + close( fd ); + continue; + } + + // Get number of joystick axes + ioctl( fd, JSIOCGAXES, &ret_data ); + _glfwJoy[ joy_count ].NumAxes = (int) ret_data; + + // Get number of joystick buttons + ioctl( fd, JSIOCGBUTTONS, &ret_data ); + _glfwJoy[ joy_count ].NumButtons = (int) ret_data; + + // Allocate memory for joystick state + _glfwJoy[ joy_count ].Axis = + (float *) malloc( sizeof(float) * + _glfwJoy[ joy_count ].NumAxes ); + if( _glfwJoy[ joy_count ].Axis == NULL ) + { + close( fd ); + continue; + } + _glfwJoy[ joy_count ].Button = + (unsigned char *) malloc( sizeof(char) * + _glfwJoy[ joy_count ].NumButtons ); + if( _glfwJoy[ joy_count ].Button == NULL ) + { + free( _glfwJoy[ joy_count ].Axis ); + close( fd ); + continue; + } + + // Clear joystick state + for( n = 0; n < _glfwJoy[ joy_count ].NumAxes; ++ n ) + { + _glfwJoy[ joy_count ].Axis[ n ] = 0.0f; + } + for( n = 0; n < _glfwJoy[ joy_count ].NumButtons; ++ n ) + { + _glfwJoy[ joy_count ].Button[ n ] = GLFW_RELEASE; + } + + // The joystick is supported and connected + _glfwJoy[ joy_count ].Present = GL_TRUE; + joy_count ++; + } + } + } + +#endif // _GLFW_USE_LINUX_JOYSTICKS + +} + + +//======================================================================== +// _glfwTerminateJoysticks() - Close all opened joystick handles +//======================================================================== + +void _glfwTerminateJoysticks( void ) +{ + +#ifdef _GLFW_USE_LINUX_JOYSTICKS + + int i; + + // Close any opened joysticks + for( i = 0; i <= GLFW_JOYSTICK_LAST; ++ i ) + { + if( _glfwJoy[ i ].Present ) + { + close( _glfwJoy[ i ].fd ); + free( _glfwJoy[ i ].Axis ); + free( _glfwJoy[ i ].Button ); + _glfwJoy[ i ].Present = GL_FALSE; + } + } + +#endif // _GLFW_USE_LINUX_JOYSTICKS + +} + + +//======================================================================== +// Empty joystick event queue +//======================================================================== + +static void pollJoystickEvents( void ) +{ + +#ifdef _GLFW_USE_LINUX_JOYSTICKS + + struct js_event e; + int i; + + // Get joystick events for all GLFW joysticks + for( i = 0; i <= GLFW_JOYSTICK_LAST; ++ i ) + { + // Is the stick present? + if( _glfwJoy[ i ].Present ) + { + // Read all queued events (non-blocking) + while( read(_glfwJoy[i].fd, &e, sizeof(struct js_event)) > 0 ) + { + // We don't care if it's an init event or not + e.type &= ~JS_EVENT_INIT; + + // Check event type + switch( e.type ) + { + case JS_EVENT_AXIS: + _glfwJoy[ i ].Axis[ e.number ] = (float) e.value / + 32767.0f; + // We need to change the sign for the Y axes, so that + // positive = up/forward, according to the GLFW spec. + if( e.number & 1 ) + { + _glfwJoy[ i ].Axis[ e.number ] = + -_glfwJoy[ i ].Axis[ e.number ]; + } + break; + + case JS_EVENT_BUTTON: + _glfwJoy[ i ].Button[ e.number ] = + e.value ? GLFW_PRESS : GLFW_RELEASE; + break; + + default: + break; + } + } + } + } + +#endif // _GLFW_USE_LINUX_JOYSTICKS + +} + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformGetJoystickParam() - Determine joystick capabilities +//======================================================================== + +int _glfwPlatformGetJoystickParam( int joy, int param ) +{ + // Is joystick present? + if( !_glfwJoy[ joy ].Present ) + { + return 0; + } + + switch( param ) + { + case GLFW_PRESENT: + return GL_TRUE; + + case GLFW_AXES: + return _glfwJoy[ joy ].NumAxes; + + case GLFW_BUTTONS: + return _glfwJoy[ joy ].NumButtons; + + default: + break; + } + + return 0; +} + + +//======================================================================== +// _glfwPlatformGetJoystickPos() - Get joystick axis positions +//======================================================================== + +int _glfwPlatformGetJoystickPos( int joy, float *pos, int numaxes ) +{ + int i; + + // Is joystick present? + if( !_glfwJoy[ joy ].Present ) + { + return 0; + } + + // Update joystick state + pollJoystickEvents(); + + // Does the joystick support less axes than requested? + if( _glfwJoy[ joy ].NumAxes < numaxes ) + { + numaxes = _glfwJoy[ joy ].NumAxes; + } + + // Copy axis positions from internal state + for( i = 0; i < numaxes; ++ i ) + { + pos[ i ] = _glfwJoy[ joy ].Axis[ i ]; + } + + return numaxes; +} + + +//======================================================================== +// _glfwPlatformGetJoystickButtons() - Get joystick button states +//======================================================================== + +int _glfwPlatformGetJoystickButtons( int joy, unsigned char *buttons, + int numbuttons ) +{ + int i; + + // Is joystick present? + if( !_glfwJoy[ joy ].Present ) + { + return 0; + } + + // Update joystick state + pollJoystickEvents(); + + // Does the joystick support less buttons than requested? + if( _glfwJoy[ joy ].NumButtons < numbuttons ) + { + numbuttons = _glfwJoy[ joy ].NumButtons; + } + + // Copy button states from internal state + for( i = 0; i < numbuttons; ++ i ) + { + buttons[ i ] = _glfwJoy[ joy ].Button[ i ]; + } + + return numbuttons; +} + diff --git a/lib/x11/x11_keysym2unicode.c b/lib/x11/x11_keysym2unicode.c new file mode 100644 index 00000000..9701cb49 --- /dev/null +++ b/lib/x11/x11_keysym2unicode.c @@ -0,0 +1,901 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: X11/GLX +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +/* + * Marcus: This code was originally written by Markus G. Kuhn. + * I have made some slight changes (trimmed it down a bit from >60 KB to + * 20 KB), but the functionality is the same. + */ + +/* + * This module converts keysym values into the corresponding ISO 10646 + * (UCS, Unicode) values. + * + * The array keysymtab[] contains pairs of X11 keysym values for graphical + * characters and the corresponding Unicode value. The function + * _glfwKeySym2Unicode() maps a keysym onto a Unicode value using a binary + * search, therefore keysymtab[] must remain SORTED by keysym value. + * + * We allow to represent any UCS character in the range U-00000000 to + * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff. + * This admittedly does not cover the entire 31-bit space of UCS, but + * it does cover all of the characters up to U-10FFFF, which can be + * represented by UTF-16, and more, and it is very unlikely that higher + * UCS codes will ever be assigned by ISO. So to get Unicode character + * U+ABCD you can directly use keysym 0x0100abcd. + * + * Original author: Markus G. Kuhn , University of + * Cambridge, April 2001 + * + * Special thanks to Richard Verhoeven for preparing + * an initial draft of the mapping table. + * + */ + + +//************************************************************************ +//**** KeySym to Unicode mapping table **** +//************************************************************************ + +static struct codepair { + unsigned short keysym; + unsigned short ucs; +} keysymtab[] = { + { 0x01a1, 0x0104 }, + { 0x01a2, 0x02d8 }, + { 0x01a3, 0x0141 }, + { 0x01a5, 0x013d }, + { 0x01a6, 0x015a }, + { 0x01a9, 0x0160 }, + { 0x01aa, 0x015e }, + { 0x01ab, 0x0164 }, + { 0x01ac, 0x0179 }, + { 0x01ae, 0x017d }, + { 0x01af, 0x017b }, + { 0x01b1, 0x0105 }, + { 0x01b2, 0x02db }, + { 0x01b3, 0x0142 }, + { 0x01b5, 0x013e }, + { 0x01b6, 0x015b }, + { 0x01b7, 0x02c7 }, + { 0x01b9, 0x0161 }, + { 0x01ba, 0x015f }, + { 0x01bb, 0x0165 }, + { 0x01bc, 0x017a }, + { 0x01bd, 0x02dd }, + { 0x01be, 0x017e }, + { 0x01bf, 0x017c }, + { 0x01c0, 0x0154 }, + { 0x01c3, 0x0102 }, + { 0x01c5, 0x0139 }, + { 0x01c6, 0x0106 }, + { 0x01c8, 0x010c }, + { 0x01ca, 0x0118 }, + { 0x01cc, 0x011a }, + { 0x01cf, 0x010e }, + { 0x01d0, 0x0110 }, + { 0x01d1, 0x0143 }, + { 0x01d2, 0x0147 }, + { 0x01d5, 0x0150 }, + { 0x01d8, 0x0158 }, + { 0x01d9, 0x016e }, + { 0x01db, 0x0170 }, + { 0x01de, 0x0162 }, + { 0x01e0, 0x0155 }, + { 0x01e3, 0x0103 }, + { 0x01e5, 0x013a }, + { 0x01e6, 0x0107 }, + { 0x01e8, 0x010d }, + { 0x01ea, 0x0119 }, + { 0x01ec, 0x011b }, + { 0x01ef, 0x010f }, + { 0x01f0, 0x0111 }, + { 0x01f1, 0x0144 }, + { 0x01f2, 0x0148 }, + { 0x01f5, 0x0151 }, + { 0x01f8, 0x0159 }, + { 0x01f9, 0x016f }, + { 0x01fb, 0x0171 }, + { 0x01fe, 0x0163 }, + { 0x01ff, 0x02d9 }, + { 0x02a1, 0x0126 }, + { 0x02a6, 0x0124 }, + { 0x02a9, 0x0130 }, + { 0x02ab, 0x011e }, + { 0x02ac, 0x0134 }, + { 0x02b1, 0x0127 }, + { 0x02b6, 0x0125 }, + { 0x02b9, 0x0131 }, + { 0x02bb, 0x011f }, + { 0x02bc, 0x0135 }, + { 0x02c5, 0x010a }, + { 0x02c6, 0x0108 }, + { 0x02d5, 0x0120 }, + { 0x02d8, 0x011c }, + { 0x02dd, 0x016c }, + { 0x02de, 0x015c }, + { 0x02e5, 0x010b }, + { 0x02e6, 0x0109 }, + { 0x02f5, 0x0121 }, + { 0x02f8, 0x011d }, + { 0x02fd, 0x016d }, + { 0x02fe, 0x015d }, + { 0x03a2, 0x0138 }, + { 0x03a3, 0x0156 }, + { 0x03a5, 0x0128 }, + { 0x03a6, 0x013b }, + { 0x03aa, 0x0112 }, + { 0x03ab, 0x0122 }, + { 0x03ac, 0x0166 }, + { 0x03b3, 0x0157 }, + { 0x03b5, 0x0129 }, + { 0x03b6, 0x013c }, + { 0x03ba, 0x0113 }, + { 0x03bb, 0x0123 }, + { 0x03bc, 0x0167 }, + { 0x03bd, 0x014a }, + { 0x03bf, 0x014b }, + { 0x03c0, 0x0100 }, + { 0x03c7, 0x012e }, + { 0x03cc, 0x0116 }, + { 0x03cf, 0x012a }, + { 0x03d1, 0x0145 }, + { 0x03d2, 0x014c }, + { 0x03d3, 0x0136 }, + { 0x03d9, 0x0172 }, + { 0x03dd, 0x0168 }, + { 0x03de, 0x016a }, + { 0x03e0, 0x0101 }, + { 0x03e7, 0x012f }, + { 0x03ec, 0x0117 }, + { 0x03ef, 0x012b }, + { 0x03f1, 0x0146 }, + { 0x03f2, 0x014d }, + { 0x03f3, 0x0137 }, + { 0x03f9, 0x0173 }, + { 0x03fd, 0x0169 }, + { 0x03fe, 0x016b }, + { 0x047e, 0x203e }, + { 0x04a1, 0x3002 }, + { 0x04a2, 0x300c }, + { 0x04a3, 0x300d }, + { 0x04a4, 0x3001 }, + { 0x04a5, 0x30fb }, + { 0x04a6, 0x30f2 }, + { 0x04a7, 0x30a1 }, + { 0x04a8, 0x30a3 }, + { 0x04a9, 0x30a5 }, + { 0x04aa, 0x30a7 }, + { 0x04ab, 0x30a9 }, + { 0x04ac, 0x30e3 }, + { 0x04ad, 0x30e5 }, + { 0x04ae, 0x30e7 }, + { 0x04af, 0x30c3 }, + { 0x04b0, 0x30fc }, + { 0x04b1, 0x30a2 }, + { 0x04b2, 0x30a4 }, + { 0x04b3, 0x30a6 }, + { 0x04b4, 0x30a8 }, + { 0x04b5, 0x30aa }, + { 0x04b6, 0x30ab }, + { 0x04b7, 0x30ad }, + { 0x04b8, 0x30af }, + { 0x04b9, 0x30b1 }, + { 0x04ba, 0x30b3 }, + { 0x04bb, 0x30b5 }, + { 0x04bc, 0x30b7 }, + { 0x04bd, 0x30b9 }, + { 0x04be, 0x30bb }, + { 0x04bf, 0x30bd }, + { 0x04c0, 0x30bf }, + { 0x04c1, 0x30c1 }, + { 0x04c2, 0x30c4 }, + { 0x04c3, 0x30c6 }, + { 0x04c4, 0x30c8 }, + { 0x04c5, 0x30ca }, + { 0x04c6, 0x30cb }, + { 0x04c7, 0x30cc }, + { 0x04c8, 0x30cd }, + { 0x04c9, 0x30ce }, + { 0x04ca, 0x30cf }, + { 0x04cb, 0x30d2 }, + { 0x04cc, 0x30d5 }, + { 0x04cd, 0x30d8 }, + { 0x04ce, 0x30db }, + { 0x04cf, 0x30de }, + { 0x04d0, 0x30df }, + { 0x04d1, 0x30e0 }, + { 0x04d2, 0x30e1 }, + { 0x04d3, 0x30e2 }, + { 0x04d4, 0x30e4 }, + { 0x04d5, 0x30e6 }, + { 0x04d6, 0x30e8 }, + { 0x04d7, 0x30e9 }, + { 0x04d8, 0x30ea }, + { 0x04d9, 0x30eb }, + { 0x04da, 0x30ec }, + { 0x04db, 0x30ed }, + { 0x04dc, 0x30ef }, + { 0x04dd, 0x30f3 }, + { 0x04de, 0x309b }, + { 0x04df, 0x309c }, + { 0x05ac, 0x060c }, + { 0x05bb, 0x061b }, + { 0x05bf, 0x061f }, + { 0x05c1, 0x0621 }, + { 0x05c2, 0x0622 }, + { 0x05c3, 0x0623 }, + { 0x05c4, 0x0624 }, + { 0x05c5, 0x0625 }, + { 0x05c6, 0x0626 }, + { 0x05c7, 0x0627 }, + { 0x05c8, 0x0628 }, + { 0x05c9, 0x0629 }, + { 0x05ca, 0x062a }, + { 0x05cb, 0x062b }, + { 0x05cc, 0x062c }, + { 0x05cd, 0x062d }, + { 0x05ce, 0x062e }, + { 0x05cf, 0x062f }, + { 0x05d0, 0x0630 }, + { 0x05d1, 0x0631 }, + { 0x05d2, 0x0632 }, + { 0x05d3, 0x0633 }, + { 0x05d4, 0x0634 }, + { 0x05d5, 0x0635 }, + { 0x05d6, 0x0636 }, + { 0x05d7, 0x0637 }, + { 0x05d8, 0x0638 }, + { 0x05d9, 0x0639 }, + { 0x05da, 0x063a }, + { 0x05e0, 0x0640 }, + { 0x05e1, 0x0641 }, + { 0x05e2, 0x0642 }, + { 0x05e3, 0x0643 }, + { 0x05e4, 0x0644 }, + { 0x05e5, 0x0645 }, + { 0x05e6, 0x0646 }, + { 0x05e7, 0x0647 }, + { 0x05e8, 0x0648 }, + { 0x05e9, 0x0649 }, + { 0x05ea, 0x064a }, + { 0x05eb, 0x064b }, + { 0x05ec, 0x064c }, + { 0x05ed, 0x064d }, + { 0x05ee, 0x064e }, + { 0x05ef, 0x064f }, + { 0x05f0, 0x0650 }, + { 0x05f1, 0x0651 }, + { 0x05f2, 0x0652 }, + { 0x06a1, 0x0452 }, + { 0x06a2, 0x0453 }, + { 0x06a3, 0x0451 }, + { 0x06a4, 0x0454 }, + { 0x06a5, 0x0455 }, + { 0x06a6, 0x0456 }, + { 0x06a7, 0x0457 }, + { 0x06a8, 0x0458 }, + { 0x06a9, 0x0459 }, + { 0x06aa, 0x045a }, + { 0x06ab, 0x045b }, + { 0x06ac, 0x045c }, + { 0x06ae, 0x045e }, + { 0x06af, 0x045f }, + { 0x06b0, 0x2116 }, + { 0x06b1, 0x0402 }, + { 0x06b2, 0x0403 }, + { 0x06b3, 0x0401 }, + { 0x06b4, 0x0404 }, + { 0x06b5, 0x0405 }, + { 0x06b6, 0x0406 }, + { 0x06b7, 0x0407 }, + { 0x06b8, 0x0408 }, + { 0x06b9, 0x0409 }, + { 0x06ba, 0x040a }, + { 0x06bb, 0x040b }, + { 0x06bc, 0x040c }, + { 0x06be, 0x040e }, + { 0x06bf, 0x040f }, + { 0x06c0, 0x044e }, + { 0x06c1, 0x0430 }, + { 0x06c2, 0x0431 }, + { 0x06c3, 0x0446 }, + { 0x06c4, 0x0434 }, + { 0x06c5, 0x0435 }, + { 0x06c6, 0x0444 }, + { 0x06c7, 0x0433 }, + { 0x06c8, 0x0445 }, + { 0x06c9, 0x0438 }, + { 0x06ca, 0x0439 }, + { 0x06cb, 0x043a }, + { 0x06cc, 0x043b }, + { 0x06cd, 0x043c }, + { 0x06ce, 0x043d }, + { 0x06cf, 0x043e }, + { 0x06d0, 0x043f }, + { 0x06d1, 0x044f }, + { 0x06d2, 0x0440 }, + { 0x06d3, 0x0441 }, + { 0x06d4, 0x0442 }, + { 0x06d5, 0x0443 }, + { 0x06d6, 0x0436 }, + { 0x06d7, 0x0432 }, + { 0x06d8, 0x044c }, + { 0x06d9, 0x044b }, + { 0x06da, 0x0437 }, + { 0x06db, 0x0448 }, + { 0x06dc, 0x044d }, + { 0x06dd, 0x0449 }, + { 0x06de, 0x0447 }, + { 0x06df, 0x044a }, + { 0x06e0, 0x042e }, + { 0x06e1, 0x0410 }, + { 0x06e2, 0x0411 }, + { 0x06e3, 0x0426 }, + { 0x06e4, 0x0414 }, + { 0x06e5, 0x0415 }, + { 0x06e6, 0x0424 }, + { 0x06e7, 0x0413 }, + { 0x06e8, 0x0425 }, + { 0x06e9, 0x0418 }, + { 0x06ea, 0x0419 }, + { 0x06eb, 0x041a }, + { 0x06ec, 0x041b }, + { 0x06ed, 0x041c }, + { 0x06ee, 0x041d }, + { 0x06ef, 0x041e }, + { 0x06f0, 0x041f }, + { 0x06f1, 0x042f }, + { 0x06f2, 0x0420 }, + { 0x06f3, 0x0421 }, + { 0x06f4, 0x0422 }, + { 0x06f5, 0x0423 }, + { 0x06f6, 0x0416 }, + { 0x06f7, 0x0412 }, + { 0x06f8, 0x042c }, + { 0x06f9, 0x042b }, + { 0x06fa, 0x0417 }, + { 0x06fb, 0x0428 }, + { 0x06fc, 0x042d }, + { 0x06fd, 0x0429 }, + { 0x06fe, 0x0427 }, + { 0x06ff, 0x042a }, + { 0x07a1, 0x0386 }, + { 0x07a2, 0x0388 }, + { 0x07a3, 0x0389 }, + { 0x07a4, 0x038a }, + { 0x07a5, 0x03aa }, + { 0x07a7, 0x038c }, + { 0x07a8, 0x038e }, + { 0x07a9, 0x03ab }, + { 0x07ab, 0x038f }, + { 0x07ae, 0x0385 }, + { 0x07af, 0x2015 }, + { 0x07b1, 0x03ac }, + { 0x07b2, 0x03ad }, + { 0x07b3, 0x03ae }, + { 0x07b4, 0x03af }, + { 0x07b5, 0x03ca }, + { 0x07b6, 0x0390 }, + { 0x07b7, 0x03cc }, + { 0x07b8, 0x03cd }, + { 0x07b9, 0x03cb }, + { 0x07ba, 0x03b0 }, + { 0x07bb, 0x03ce }, + { 0x07c1, 0x0391 }, + { 0x07c2, 0x0392 }, + { 0x07c3, 0x0393 }, + { 0x07c4, 0x0394 }, + { 0x07c5, 0x0395 }, + { 0x07c6, 0x0396 }, + { 0x07c7, 0x0397 }, + { 0x07c8, 0x0398 }, + { 0x07c9, 0x0399 }, + { 0x07ca, 0x039a }, + { 0x07cb, 0x039b }, + { 0x07cc, 0x039c }, + { 0x07cd, 0x039d }, + { 0x07ce, 0x039e }, + { 0x07cf, 0x039f }, + { 0x07d0, 0x03a0 }, + { 0x07d1, 0x03a1 }, + { 0x07d2, 0x03a3 }, + { 0x07d4, 0x03a4 }, + { 0x07d5, 0x03a5 }, + { 0x07d6, 0x03a6 }, + { 0x07d7, 0x03a7 }, + { 0x07d8, 0x03a8 }, + { 0x07d9, 0x03a9 }, + { 0x07e1, 0x03b1 }, + { 0x07e2, 0x03b2 }, + { 0x07e3, 0x03b3 }, + { 0x07e4, 0x03b4 }, + { 0x07e5, 0x03b5 }, + { 0x07e6, 0x03b6 }, + { 0x07e7, 0x03b7 }, + { 0x07e8, 0x03b8 }, + { 0x07e9, 0x03b9 }, + { 0x07ea, 0x03ba }, + { 0x07eb, 0x03bb }, + { 0x07ec, 0x03bc }, + { 0x07ed, 0x03bd }, + { 0x07ee, 0x03be }, + { 0x07ef, 0x03bf }, + { 0x07f0, 0x03c0 }, + { 0x07f1, 0x03c1 }, + { 0x07f2, 0x03c3 }, + { 0x07f3, 0x03c2 }, + { 0x07f4, 0x03c4 }, + { 0x07f5, 0x03c5 }, + { 0x07f6, 0x03c6 }, + { 0x07f7, 0x03c7 }, + { 0x07f8, 0x03c8 }, + { 0x07f9, 0x03c9 }, + { 0x08a1, 0x23b7 }, + { 0x08a2, 0x250c }, + { 0x08a3, 0x2500 }, + { 0x08a4, 0x2320 }, + { 0x08a5, 0x2321 }, + { 0x08a6, 0x2502 }, + { 0x08a7, 0x23a1 }, + { 0x08a8, 0x23a3 }, + { 0x08a9, 0x23a4 }, + { 0x08aa, 0x23a6 }, + { 0x08ab, 0x239b }, + { 0x08ac, 0x239d }, + { 0x08ad, 0x239e }, + { 0x08ae, 0x23a0 }, + { 0x08af, 0x23a8 }, + { 0x08b0, 0x23ac }, + { 0x08bc, 0x2264 }, + { 0x08bd, 0x2260 }, + { 0x08be, 0x2265 }, + { 0x08bf, 0x222b }, + { 0x08c0, 0x2234 }, + { 0x08c1, 0x221d }, + { 0x08c2, 0x221e }, + { 0x08c5, 0x2207 }, + { 0x08c8, 0x223c }, + { 0x08c9, 0x2243 }, + { 0x08cd, 0x21d4 }, + { 0x08ce, 0x21d2 }, + { 0x08cf, 0x2261 }, + { 0x08d6, 0x221a }, + { 0x08da, 0x2282 }, + { 0x08db, 0x2283 }, + { 0x08dc, 0x2229 }, + { 0x08dd, 0x222a }, + { 0x08de, 0x2227 }, + { 0x08df, 0x2228 }, + { 0x08ef, 0x2202 }, + { 0x08f6, 0x0192 }, + { 0x08fb, 0x2190 }, + { 0x08fc, 0x2191 }, + { 0x08fd, 0x2192 }, + { 0x08fe, 0x2193 }, + { 0x09e0, 0x25c6 }, + { 0x09e1, 0x2592 }, + { 0x09e2, 0x2409 }, + { 0x09e3, 0x240c }, + { 0x09e4, 0x240d }, + { 0x09e5, 0x240a }, + { 0x09e8, 0x2424 }, + { 0x09e9, 0x240b }, + { 0x09ea, 0x2518 }, + { 0x09eb, 0x2510 }, + { 0x09ec, 0x250c }, + { 0x09ed, 0x2514 }, + { 0x09ee, 0x253c }, + { 0x09ef, 0x23ba }, + { 0x09f0, 0x23bb }, + { 0x09f1, 0x2500 }, + { 0x09f2, 0x23bc }, + { 0x09f3, 0x23bd }, + { 0x09f4, 0x251c }, + { 0x09f5, 0x2524 }, + { 0x09f6, 0x2534 }, + { 0x09f7, 0x252c }, + { 0x09f8, 0x2502 }, + { 0x0aa1, 0x2003 }, + { 0x0aa2, 0x2002 }, + { 0x0aa3, 0x2004 }, + { 0x0aa4, 0x2005 }, + { 0x0aa5, 0x2007 }, + { 0x0aa6, 0x2008 }, + { 0x0aa7, 0x2009 }, + { 0x0aa8, 0x200a }, + { 0x0aa9, 0x2014 }, + { 0x0aaa, 0x2013 }, + { 0x0aae, 0x2026 }, + { 0x0aaf, 0x2025 }, + { 0x0ab0, 0x2153 }, + { 0x0ab1, 0x2154 }, + { 0x0ab2, 0x2155 }, + { 0x0ab3, 0x2156 }, + { 0x0ab4, 0x2157 }, + { 0x0ab5, 0x2158 }, + { 0x0ab6, 0x2159 }, + { 0x0ab7, 0x215a }, + { 0x0ab8, 0x2105 }, + { 0x0abb, 0x2012 }, + { 0x0abc, 0x2329 }, + { 0x0abe, 0x232a }, + { 0x0ac3, 0x215b }, + { 0x0ac4, 0x215c }, + { 0x0ac5, 0x215d }, + { 0x0ac6, 0x215e }, + { 0x0ac9, 0x2122 }, + { 0x0aca, 0x2613 }, + { 0x0acc, 0x25c1 }, + { 0x0acd, 0x25b7 }, + { 0x0ace, 0x25cb }, + { 0x0acf, 0x25af }, + { 0x0ad0, 0x2018 }, + { 0x0ad1, 0x2019 }, + { 0x0ad2, 0x201c }, + { 0x0ad3, 0x201d }, + { 0x0ad4, 0x211e }, + { 0x0ad6, 0x2032 }, + { 0x0ad7, 0x2033 }, + { 0x0ad9, 0x271d }, + { 0x0adb, 0x25ac }, + { 0x0adc, 0x25c0 }, + { 0x0add, 0x25b6 }, + { 0x0ade, 0x25cf }, + { 0x0adf, 0x25ae }, + { 0x0ae0, 0x25e6 }, + { 0x0ae1, 0x25ab }, + { 0x0ae2, 0x25ad }, + { 0x0ae3, 0x25b3 }, + { 0x0ae4, 0x25bd }, + { 0x0ae5, 0x2606 }, + { 0x0ae6, 0x2022 }, + { 0x0ae7, 0x25aa }, + { 0x0ae8, 0x25b2 }, + { 0x0ae9, 0x25bc }, + { 0x0aea, 0x261c }, + { 0x0aeb, 0x261e }, + { 0x0aec, 0x2663 }, + { 0x0aed, 0x2666 }, + { 0x0aee, 0x2665 }, + { 0x0af0, 0x2720 }, + { 0x0af1, 0x2020 }, + { 0x0af2, 0x2021 }, + { 0x0af3, 0x2713 }, + { 0x0af4, 0x2717 }, + { 0x0af5, 0x266f }, + { 0x0af6, 0x266d }, + { 0x0af7, 0x2642 }, + { 0x0af8, 0x2640 }, + { 0x0af9, 0x260e }, + { 0x0afa, 0x2315 }, + { 0x0afb, 0x2117 }, + { 0x0afc, 0x2038 }, + { 0x0afd, 0x201a }, + { 0x0afe, 0x201e }, + { 0x0ba3, 0x003c }, + { 0x0ba6, 0x003e }, + { 0x0ba8, 0x2228 }, + { 0x0ba9, 0x2227 }, + { 0x0bc0, 0x00af }, + { 0x0bc2, 0x22a5 }, + { 0x0bc3, 0x2229 }, + { 0x0bc4, 0x230a }, + { 0x0bc6, 0x005f }, + { 0x0bca, 0x2218 }, + { 0x0bcc, 0x2395 }, + { 0x0bce, 0x22a4 }, + { 0x0bcf, 0x25cb }, + { 0x0bd3, 0x2308 }, + { 0x0bd6, 0x222a }, + { 0x0bd8, 0x2283 }, + { 0x0bda, 0x2282 }, + { 0x0bdc, 0x22a2 }, + { 0x0bfc, 0x22a3 }, + { 0x0cdf, 0x2017 }, + { 0x0ce0, 0x05d0 }, + { 0x0ce1, 0x05d1 }, + { 0x0ce2, 0x05d2 }, + { 0x0ce3, 0x05d3 }, + { 0x0ce4, 0x05d4 }, + { 0x0ce5, 0x05d5 }, + { 0x0ce6, 0x05d6 }, + { 0x0ce7, 0x05d7 }, + { 0x0ce8, 0x05d8 }, + { 0x0ce9, 0x05d9 }, + { 0x0cea, 0x05da }, + { 0x0ceb, 0x05db }, + { 0x0cec, 0x05dc }, + { 0x0ced, 0x05dd }, + { 0x0cee, 0x05de }, + { 0x0cef, 0x05df }, + { 0x0cf0, 0x05e0 }, + { 0x0cf1, 0x05e1 }, + { 0x0cf2, 0x05e2 }, + { 0x0cf3, 0x05e3 }, + { 0x0cf4, 0x05e4 }, + { 0x0cf5, 0x05e5 }, + { 0x0cf6, 0x05e6 }, + { 0x0cf7, 0x05e7 }, + { 0x0cf8, 0x05e8 }, + { 0x0cf9, 0x05e9 }, + { 0x0cfa, 0x05ea }, + { 0x0da1, 0x0e01 }, + { 0x0da2, 0x0e02 }, + { 0x0da3, 0x0e03 }, + { 0x0da4, 0x0e04 }, + { 0x0da5, 0x0e05 }, + { 0x0da6, 0x0e06 }, + { 0x0da7, 0x0e07 }, + { 0x0da8, 0x0e08 }, + { 0x0da9, 0x0e09 }, + { 0x0daa, 0x0e0a }, + { 0x0dab, 0x0e0b }, + { 0x0dac, 0x0e0c }, + { 0x0dad, 0x0e0d }, + { 0x0dae, 0x0e0e }, + { 0x0daf, 0x0e0f }, + { 0x0db0, 0x0e10 }, + { 0x0db1, 0x0e11 }, + { 0x0db2, 0x0e12 }, + { 0x0db3, 0x0e13 }, + { 0x0db4, 0x0e14 }, + { 0x0db5, 0x0e15 }, + { 0x0db6, 0x0e16 }, + { 0x0db7, 0x0e17 }, + { 0x0db8, 0x0e18 }, + { 0x0db9, 0x0e19 }, + { 0x0dba, 0x0e1a }, + { 0x0dbb, 0x0e1b }, + { 0x0dbc, 0x0e1c }, + { 0x0dbd, 0x0e1d }, + { 0x0dbe, 0x0e1e }, + { 0x0dbf, 0x0e1f }, + { 0x0dc0, 0x0e20 }, + { 0x0dc1, 0x0e21 }, + { 0x0dc2, 0x0e22 }, + { 0x0dc3, 0x0e23 }, + { 0x0dc4, 0x0e24 }, + { 0x0dc5, 0x0e25 }, + { 0x0dc6, 0x0e26 }, + { 0x0dc7, 0x0e27 }, + { 0x0dc8, 0x0e28 }, + { 0x0dc9, 0x0e29 }, + { 0x0dca, 0x0e2a }, + { 0x0dcb, 0x0e2b }, + { 0x0dcc, 0x0e2c }, + { 0x0dcd, 0x0e2d }, + { 0x0dce, 0x0e2e }, + { 0x0dcf, 0x0e2f }, + { 0x0dd0, 0x0e30 }, + { 0x0dd1, 0x0e31 }, + { 0x0dd2, 0x0e32 }, + { 0x0dd3, 0x0e33 }, + { 0x0dd4, 0x0e34 }, + { 0x0dd5, 0x0e35 }, + { 0x0dd6, 0x0e36 }, + { 0x0dd7, 0x0e37 }, + { 0x0dd8, 0x0e38 }, + { 0x0dd9, 0x0e39 }, + { 0x0dda, 0x0e3a }, + { 0x0ddf, 0x0e3f }, + { 0x0de0, 0x0e40 }, + { 0x0de1, 0x0e41 }, + { 0x0de2, 0x0e42 }, + { 0x0de3, 0x0e43 }, + { 0x0de4, 0x0e44 }, + { 0x0de5, 0x0e45 }, + { 0x0de6, 0x0e46 }, + { 0x0de7, 0x0e47 }, + { 0x0de8, 0x0e48 }, + { 0x0de9, 0x0e49 }, + { 0x0dea, 0x0e4a }, + { 0x0deb, 0x0e4b }, + { 0x0dec, 0x0e4c }, + { 0x0ded, 0x0e4d }, + { 0x0df0, 0x0e50 }, + { 0x0df1, 0x0e51 }, + { 0x0df2, 0x0e52 }, + { 0x0df3, 0x0e53 }, + { 0x0df4, 0x0e54 }, + { 0x0df5, 0x0e55 }, + { 0x0df6, 0x0e56 }, + { 0x0df7, 0x0e57 }, + { 0x0df8, 0x0e58 }, + { 0x0df9, 0x0e59 }, + { 0x0ea1, 0x3131 }, + { 0x0ea2, 0x3132 }, + { 0x0ea3, 0x3133 }, + { 0x0ea4, 0x3134 }, + { 0x0ea5, 0x3135 }, + { 0x0ea6, 0x3136 }, + { 0x0ea7, 0x3137 }, + { 0x0ea8, 0x3138 }, + { 0x0ea9, 0x3139 }, + { 0x0eaa, 0x313a }, + { 0x0eab, 0x313b }, + { 0x0eac, 0x313c }, + { 0x0ead, 0x313d }, + { 0x0eae, 0x313e }, + { 0x0eaf, 0x313f }, + { 0x0eb0, 0x3140 }, + { 0x0eb1, 0x3141 }, + { 0x0eb2, 0x3142 }, + { 0x0eb3, 0x3143 }, + { 0x0eb4, 0x3144 }, + { 0x0eb5, 0x3145 }, + { 0x0eb6, 0x3146 }, + { 0x0eb7, 0x3147 }, + { 0x0eb8, 0x3148 }, + { 0x0eb9, 0x3149 }, + { 0x0eba, 0x314a }, + { 0x0ebb, 0x314b }, + { 0x0ebc, 0x314c }, + { 0x0ebd, 0x314d }, + { 0x0ebe, 0x314e }, + { 0x0ebf, 0x314f }, + { 0x0ec0, 0x3150 }, + { 0x0ec1, 0x3151 }, + { 0x0ec2, 0x3152 }, + { 0x0ec3, 0x3153 }, + { 0x0ec4, 0x3154 }, + { 0x0ec5, 0x3155 }, + { 0x0ec6, 0x3156 }, + { 0x0ec7, 0x3157 }, + { 0x0ec8, 0x3158 }, + { 0x0ec9, 0x3159 }, + { 0x0eca, 0x315a }, + { 0x0ecb, 0x315b }, + { 0x0ecc, 0x315c }, + { 0x0ecd, 0x315d }, + { 0x0ece, 0x315e }, + { 0x0ecf, 0x315f }, + { 0x0ed0, 0x3160 }, + { 0x0ed1, 0x3161 }, + { 0x0ed2, 0x3162 }, + { 0x0ed3, 0x3163 }, + { 0x0ed4, 0x11a8 }, + { 0x0ed5, 0x11a9 }, + { 0x0ed6, 0x11aa }, + { 0x0ed7, 0x11ab }, + { 0x0ed8, 0x11ac }, + { 0x0ed9, 0x11ad }, + { 0x0eda, 0x11ae }, + { 0x0edb, 0x11af }, + { 0x0edc, 0x11b0 }, + { 0x0edd, 0x11b1 }, + { 0x0ede, 0x11b2 }, + { 0x0edf, 0x11b3 }, + { 0x0ee0, 0x11b4 }, + { 0x0ee1, 0x11b5 }, + { 0x0ee2, 0x11b6 }, + { 0x0ee3, 0x11b7 }, + { 0x0ee4, 0x11b8 }, + { 0x0ee5, 0x11b9 }, + { 0x0ee6, 0x11ba }, + { 0x0ee7, 0x11bb }, + { 0x0ee8, 0x11bc }, + { 0x0ee9, 0x11bd }, + { 0x0eea, 0x11be }, + { 0x0eeb, 0x11bf }, + { 0x0eec, 0x11c0 }, + { 0x0eed, 0x11c1 }, + { 0x0eee, 0x11c2 }, + { 0x0eef, 0x316d }, + { 0x0ef0, 0x3171 }, + { 0x0ef1, 0x3178 }, + { 0x0ef2, 0x317f }, + { 0x0ef3, 0x3181 }, + { 0x0ef4, 0x3184 }, + { 0x0ef5, 0x3186 }, + { 0x0ef6, 0x318d }, + { 0x0ef7, 0x318e }, + { 0x0ef8, 0x11eb }, + { 0x0ef9, 0x11f0 }, + { 0x0efa, 0x11f9 }, + { 0x0eff, 0x20a9 }, + { 0x13a4, 0x20ac }, + { 0x13bc, 0x0152 }, + { 0x13bd, 0x0153 }, + { 0x13be, 0x0178 }, + { 0x20ac, 0x20ac }, + // Numeric keypad with numlock on + { XK_KP_Space, ' ' }, + { XK_KP_Equal, '=' }, + { XK_KP_Multiply, '*' }, + { XK_KP_Add, '+' }, + { XK_KP_Separator, ',' }, + { XK_KP_Subtract, '-' }, + { XK_KP_Decimal, '.' }, + { XK_KP_Divide, '/' }, + { XK_KP_0, 0x0030 }, + { XK_KP_1, 0x0031 }, + { XK_KP_2, 0x0032 }, + { XK_KP_3, 0x0033 }, + { XK_KP_4, 0x0034 }, + { XK_KP_5, 0x0035 }, + { XK_KP_6, 0x0036 }, + { XK_KP_7, 0x0037 }, + { XK_KP_8, 0x0038 }, + { XK_KP_9, 0x0039 } +}; + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwKeySym2Unicode() - Convert X11 KeySym to Unicode +//======================================================================== + +long _glfwKeySym2Unicode( KeySym keysym ) +{ + int min = 0; + int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; + int mid; + + /* First check for Latin-1 characters (1:1 mapping) */ + if( (keysym >= 0x0020 && keysym <= 0x007e) || + (keysym >= 0x00a0 && keysym <= 0x00ff) ) + { return keysym; + } + + /* Also check for directly encoded 24-bit UCS characters */ + if( (keysym & 0xff000000) == 0x01000000 ) + { + return keysym & 0x00ffffff; + } + + /* Binary search in table */ + while( max >= min ) + { + mid = (min + max) / 2; + if( keysymtab[mid].keysym < keysym ) + { + min = mid + 1; + } + else if( keysymtab[mid].keysym > keysym ) + { + max = mid - 1; + } + else + { + /* Found it! */ + return keysymtab[mid].ucs; + } + } + + /* No matching Unicode value found */ + return -1; +} diff --git a/lib/x11/x11_time.c b/lib/x11/x11_time.c new file mode 100644 index 00000000..0cff709f --- /dev/null +++ b/lib/x11/x11_time.c @@ -0,0 +1,89 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: X11/GLX +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + + +//======================================================================== +// Initialise timer +//======================================================================== + +void _glfwInitTimer( void ) +{ + struct timeval tv; + + // "Resolution" is 1 us + _glfwLibrary.Timer.resolution = 1e-6; + + // Set start-time for timer + gettimeofday( &tv, NULL ); + _glfwLibrary.Timer.t0 = (long long) tv.tv_sec * (long long) 1000000 + + (long long) tv.tv_usec; +} + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Return timer value in seconds +//======================================================================== + +double _glfwPlatformGetTime( void ) +{ + long long t; + struct timeval tv; + + gettimeofday( &tv, NULL ); + t = (long long) tv.tv_sec * (long long) 1000000 + + (long long) tv.tv_usec; + + return (double)(t - _glfwLibrary.Timer.t0) * _glfwLibrary.Timer.resolution; +} + + +//======================================================================== +// Set timer value in seconds +//======================================================================== + +void _glfwPlatformSetTime( double t ) +{ + long long t0; + struct timeval tv; + + gettimeofday( &tv, NULL ); + t0 = (long long) tv.tv_sec * (long long) 1000000 + + (long long) tv.tv_usec; + + // Calulate new starting time + _glfwLibrary.Timer.t0 = t0 - (long long)(t/_glfwLibrary.Timer.resolution); +} + diff --git a/lib/x11/x11_window.c b/lib/x11/x11_window.c new file mode 100644 index 00000000..e382e8ed --- /dev/null +++ b/lib/x11/x11_window.c @@ -0,0 +1,1875 @@ +//======================================================================== +// GLFW - An OpenGL framework +// Platform: X11/GLX +// API version: 2.7 +// WWW: http://www.glfw.org/ +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include "internal.h" + +#include + + +/* Define GLX 1.4 FSAA tokens if not already defined */ +#ifndef GLX_VERSION_1_4 + +#define GLX_SAMPLE_BUFFERS 100000 +#define GLX_SAMPLES 100001 + +#endif /*GLX_VERSION_1_4*/ + +// Action for EWMH client messages +#define _NET_WM_STATE_REMOVE 0 +#define _NET_WM_STATE_ADD 1 +#define _NET_WM_STATE_TOGGLE 2 + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// Checks whether the event is a MapNotify for the specified window +//======================================================================== + +static Bool isMapNotify( Display *d, XEvent *e, char *arg ) +{ + return (e->type == MapNotify) && (e->xmap.window == (Window)arg); +} + + +//======================================================================== +// Retrieve a single window property of the specified type +// Inspired by fghGetWindowProperty from freeglut +//======================================================================== + +static unsigned long getWindowProperty( Window window, + Atom property, + Atom type, + unsigned char** value ) +{ + Atom actualType; + int actualFormat; + unsigned long itemCount, bytesAfter; + + XGetWindowProperty( _glfwLibrary.display, + window, + property, + 0, + LONG_MAX, + False, + type, + &actualType, + &actualFormat, + &itemCount, + &bytesAfter, + value ); + + if( actualType != type ) + { + return 0; + } + + return itemCount; +} + + +//======================================================================== +// Check whether the specified atom is supported +//======================================================================== + +static Atom getSupportedAtom( Atom* supportedAtoms, + unsigned long atomCount, + const char* atomName ) +{ + Atom atom = XInternAtom( _glfwLibrary.display, atomName, True ); + if( atom != None ) + { + unsigned long i; + + for( i = 0; i < atomCount; i++ ) + { + if( supportedAtoms[i] == atom ) + { + return atom; + } + } + } + + return None; +} + + +//======================================================================== +// Check whether the running window manager is EWMH-compliant +//======================================================================== + +static GLboolean checkForEWMH( void ) +{ + Window *windowFromRoot = NULL; + Window *windowFromChild = NULL; + + // Hey kids; let's see if the window manager supports EWMH! + + // First we need a couple of atoms, which should already be there + Atom supportingWmCheck = XInternAtom( _glfwLibrary.display, + "_NET_SUPPORTING_WM_CHECK", + True ); + Atom wmSupported = XInternAtom( _glfwLibrary.display, + "_NET_SUPPORTED", + True ); + if( supportingWmCheck == None || wmSupported == None ) + { + return GL_FALSE; + } + + // Then we look for the _NET_SUPPORTING_WM_CHECK property of the root window + if( getWindowProperty( _glfwWin.root, + supportingWmCheck, + XA_WINDOW, + (unsigned char**) &windowFromRoot ) != 1 ) + { + XFree( windowFromRoot ); + return GL_FALSE; + } + + // It should be the ID of a child window (of the root) + // Then we look for the same property on the child window + if( getWindowProperty( *windowFromRoot, + supportingWmCheck, + XA_WINDOW, + (unsigned char**) &windowFromChild ) != 1 ) + { + XFree( windowFromRoot ); + XFree( windowFromChild ); + return GL_FALSE; + } + + // It should be the ID of that same child window + if( *windowFromRoot != *windowFromChild ) + { + XFree( windowFromRoot ); + XFree( windowFromChild ); + return GL_FALSE; + } + + XFree( windowFromRoot ); + XFree( windowFromChild ); + + // We are now fairly sure that an EWMH-compliant window manager is running + + Atom *supportedAtoms; + unsigned long atomCount; + + // Now we need to check the _NET_SUPPORTED property of the root window + atomCount = getWindowProperty( _glfwWin.root, + wmSupported, + XA_ATOM, + (unsigned char**) &supportedAtoms ); + + // See which of the atoms we support that are supported by the WM + + _glfwWin.wmState = getSupportedAtom( supportedAtoms, + atomCount, + "_NET_WM_STATE" ); + + _glfwWin.wmStateFullscreen = getSupportedAtom( supportedAtoms, + atomCount, + "_NET_WM_STATE_FULLSCREEN" ); + + _glfwWin.wmPing = getSupportedAtom( supportedAtoms, + atomCount, + "_NET_WM_PING" ); + + _glfwWin.wmActiveWindow = getSupportedAtom( supportedAtoms, + atomCount, + "_NET_ACTIVE_WINDOW" ); + + XFree( supportedAtoms ); + + return GL_TRUE; +} + +//======================================================================== +// Translates an X Window key to internal coding +//======================================================================== + +static int translateKey( int keycode ) +{ + KeySym key, key_lc, key_uc; + + // Try secondary keysym, for numeric keypad keys + // Note: This way we always force "NumLock = ON", which at least + // enables GLFW users to detect numeric keypad keys + key = XKeycodeToKeysym( _glfwLibrary.display, keycode, 1 ); + switch( key ) + { + // Numeric keypad + case XK_KP_0: return GLFW_KEY_KP_0; + case XK_KP_1: return GLFW_KEY_KP_1; + case XK_KP_2: return GLFW_KEY_KP_2; + case XK_KP_3: return GLFW_KEY_KP_3; + case XK_KP_4: return GLFW_KEY_KP_4; + case XK_KP_5: return GLFW_KEY_KP_5; + case XK_KP_6: return GLFW_KEY_KP_6; + case XK_KP_7: return GLFW_KEY_KP_7; + case XK_KP_8: return GLFW_KEY_KP_8; + case XK_KP_9: return GLFW_KEY_KP_9; + case XK_KP_Separator: + case XK_KP_Decimal: return GLFW_KEY_KP_DECIMAL; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + default: break; + } + + // Now try pimary keysym + key = XKeycodeToKeysym( _glfwLibrary.display, keycode, 0 ); + switch( key ) + { + // Special keys (non character keys) + case XK_Escape: return GLFW_KEY_ESC; + case XK_Tab: return GLFW_KEY_TAB; + case XK_Shift_L: return GLFW_KEY_LSHIFT; + case XK_Shift_R: return GLFW_KEY_RSHIFT; + case XK_Control_L: return GLFW_KEY_LCTRL; + case XK_Control_R: return GLFW_KEY_RCTRL; + case XK_Meta_L: + case XK_Alt_L: return GLFW_KEY_LALT; + case XK_Mode_switch: // Mapped to Alt_R on many keyboards + case XK_Meta_R: + case XK_ISO_Level3_Shift: // AltGr on at least some machines + case XK_Alt_R: return GLFW_KEY_RALT; + case XK_Super_L: return GLFW_KEY_LSUPER; + case XK_Super_R: return GLFW_KEY_RSUPER; + case XK_Menu: return GLFW_KEY_MENU; + case XK_Num_Lock: return GLFW_KEY_KP_NUM_LOCK; + case XK_Caps_Lock: return GLFW_KEY_CAPS_LOCK; + case XK_Scroll_Lock: return GLFW_KEY_SCROLL_LOCK; + case XK_Pause: return GLFW_KEY_PAUSE; + case XK_KP_Delete: + case XK_Delete: return GLFW_KEY_DEL; + case XK_BackSpace: return GLFW_KEY_BACKSPACE; + case XK_Return: return GLFW_KEY_ENTER; + case XK_KP_Home: + case XK_Home: return GLFW_KEY_HOME; + case XK_KP_End: + case XK_End: return GLFW_KEY_END; + case XK_KP_Page_Up: + case XK_Page_Up: return GLFW_KEY_PAGEUP; + case XK_KP_Page_Down: + case XK_Page_Down: return GLFW_KEY_PAGEDOWN; + case XK_KP_Insert: + case XK_Insert: return GLFW_KEY_INSERT; + case XK_KP_Left: + case XK_Left: return GLFW_KEY_LEFT; + case XK_KP_Right: + case XK_Right: return GLFW_KEY_RIGHT; + case XK_KP_Down: + case XK_Down: return GLFW_KEY_DOWN; + case XK_KP_Up: + case XK_Up: return GLFW_KEY_UP; + case XK_F1: return GLFW_KEY_F1; + case XK_F2: return GLFW_KEY_F2; + case XK_F3: return GLFW_KEY_F3; + case XK_F4: return GLFW_KEY_F4; + case XK_F5: return GLFW_KEY_F5; + case XK_F6: return GLFW_KEY_F6; + case XK_F7: return GLFW_KEY_F7; + case XK_F8: return GLFW_KEY_F8; + case XK_F9: return GLFW_KEY_F9; + case XK_F10: return GLFW_KEY_F10; + case XK_F11: return GLFW_KEY_F11; + case XK_F12: return GLFW_KEY_F12; + case XK_F13: return GLFW_KEY_F13; + case XK_F14: return GLFW_KEY_F14; + case XK_F15: return GLFW_KEY_F15; + case XK_F16: return GLFW_KEY_F16; + case XK_F17: return GLFW_KEY_F17; + case XK_F18: return GLFW_KEY_F18; + case XK_F19: return GLFW_KEY_F19; + case XK_F20: return GLFW_KEY_F20; + case XK_F21: return GLFW_KEY_F21; + case XK_F22: return GLFW_KEY_F22; + case XK_F23: return GLFW_KEY_F23; + case XK_F24: return GLFW_KEY_F24; + case XK_F25: return GLFW_KEY_F25; + + // Numeric keypad (should have been detected in secondary keysym!) + case XK_KP_Divide: return GLFW_KEY_KP_DIVIDE; + case XK_KP_Multiply: return GLFW_KEY_KP_MULTIPLY; + case XK_KP_Subtract: return GLFW_KEY_KP_SUBTRACT; + case XK_KP_Add: return GLFW_KEY_KP_ADD; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + + // The rest (should be printable keys) + default: + // Make uppercase + XConvertCase( key, &key_lc, &key_uc ); + key = key_uc; + + // Valid ISO 8859-1 character? + if( (key >= 32 && key <= 126) || + (key >= 160 && key <= 255) ) + { + return (int) key; + } + return GLFW_KEY_UNKNOWN; + } +} + + +//======================================================================== +// Translates an X Window event to Unicode +//======================================================================== + +static int translateChar( XKeyEvent *event ) +{ + KeySym keysym; + + // Get X11 keysym + XLookupString( event, NULL, 0, &keysym, NULL ); + + // Convert to Unicode (see x11_keysym2unicode.c) + return (int) _glfwKeySym2Unicode( keysym ); +} + + +//======================================================================== +// Create a blank cursor (for locked mouse mode) +//======================================================================== + +static Cursor createNULLCursor( Display *display, Window root ) +{ + Pixmap cursormask; + XGCValues xgc; + GC gc; + XColor col; + Cursor cursor; + + cursormask = XCreatePixmap( display, root, 1, 1, 1 ); + xgc.function = GXclear; + gc = XCreateGC( display, cursormask, GCFunction, &xgc ); + XFillRectangle( display, cursormask, gc, 0, 0, 1, 1 ); + col.pixel = 0; + col.red = 0; + col.flags = 4; + cursor = XCreatePixmapCursor( display, cursormask, cursormask, + &col,&col, 0,0 ); + XFreePixmap( display, cursormask ); + XFreeGC( display, gc ); + + return cursor; +} + + +//======================================================================== +// Returns the specified attribute of the specified GLXFBConfig +// NOTE: Do not call this unless we have found GLX 1.3+ or GLX_SGIX_fbconfig +//======================================================================== + +static int getFBConfigAttrib( GLXFBConfig fbconfig, int attrib ) +{ + int value; + + if( _glfwWin.has_GLX_SGIX_fbconfig ) + { + _glfwWin.GetFBConfigAttribSGIX( _glfwLibrary.display, fbconfig, attrib, &value ); + } + else + { + glXGetFBConfigAttrib( _glfwLibrary.display, fbconfig, attrib, &value ); + } + + return value; +} + + +//======================================================================== +// Return a list of available and usable framebuffer configs +//======================================================================== + +static _GLFWfbconfig *getFBConfigs( unsigned int *found ) +{ + GLXFBConfig *fbconfigs; + _GLFWfbconfig *result; + int i, count = 0; + + *found = 0; + + if( _glfwLibrary.glxMajor == 1 && _glfwLibrary.glxMinor < 3 ) + { + if( !_glfwWin.has_GLX_SGIX_fbconfig ) + { + fprintf( stderr, "GLXFBConfigs are not supported by the X server\n" ); + return NULL; + } + } + + if( _glfwWin.has_GLX_SGIX_fbconfig ) + { + fbconfigs = _glfwWin.ChooseFBConfigSGIX( _glfwLibrary.display, + _glfwWin.screen, + NULL, + &count ); + if( !count ) + { + fprintf( stderr, "No GLXFBConfigs returned\n" ); + return NULL; + } + } + else + { + fbconfigs = glXGetFBConfigs( _glfwLibrary.display, _glfwWin.screen, &count ); + if( !count ) + { + fprintf( stderr, "No GLXFBConfigs returned\n" ); + return NULL; + } + } + + result = (_GLFWfbconfig*) malloc( sizeof(_GLFWfbconfig) * count ); + if( !result ) + { + fprintf( stderr, "Out of memory\n" ); + return NULL; + } + + for( i = 0; i < count; i++ ) + { + if( !getFBConfigAttrib( fbconfigs[i], GLX_DOUBLEBUFFER ) || + !getFBConfigAttrib( fbconfigs[i], GLX_VISUAL_ID ) ) + { + // Only consider double-buffered GLXFBConfigs with associated visuals + continue; + } + + if( !( getFBConfigAttrib( fbconfigs[i], GLX_RENDER_TYPE ) & GLX_RGBA_BIT ) ) + { + // Only consider RGBA GLXFBConfigs + continue; + } + + if( !( getFBConfigAttrib( fbconfigs[i], GLX_DRAWABLE_TYPE ) & GLX_WINDOW_BIT ) ) + { + // Only consider window GLXFBConfigs + continue; + } + + result[*found].redBits = getFBConfigAttrib( fbconfigs[i], GLX_RED_SIZE ); + result[*found].greenBits = getFBConfigAttrib( fbconfigs[i], GLX_GREEN_SIZE ); + result[*found].blueBits = getFBConfigAttrib( fbconfigs[i], GLX_BLUE_SIZE ); + + result[*found].alphaBits = getFBConfigAttrib( fbconfigs[i], GLX_ALPHA_SIZE ); + result[*found].depthBits = getFBConfigAttrib( fbconfigs[i], GLX_DEPTH_SIZE ); + result[*found].stencilBits = getFBConfigAttrib( fbconfigs[i], GLX_STENCIL_SIZE ); + + result[*found].accumRedBits = getFBConfigAttrib( fbconfigs[i], GLX_ACCUM_RED_SIZE ); + result[*found].accumGreenBits = getFBConfigAttrib( fbconfigs[i], GLX_ACCUM_GREEN_SIZE ); + result[*found].accumBlueBits = getFBConfigAttrib( fbconfigs[i], GLX_ACCUM_BLUE_SIZE ); + result[*found].accumAlphaBits = getFBConfigAttrib( fbconfigs[i], GLX_ACCUM_ALPHA_SIZE ); + + result[*found].auxBuffers = getFBConfigAttrib( fbconfigs[i], GLX_AUX_BUFFERS ); + result[*found].stereo = getFBConfigAttrib( fbconfigs[i], GLX_STEREO ); + + if( _glfwWin.has_GLX_ARB_multisample ) + { + result[*found].samples = getFBConfigAttrib( fbconfigs[i], GLX_SAMPLES ); + } + else + { + result[*found].samples = 0; + } + + result[*found].platformID = (GLFWintptr) getFBConfigAttrib( fbconfigs[i], GLX_FBCONFIG_ID ); + + (*found)++; + } + + XFree( fbconfigs ); + + return result; +} + + +//======================================================================== +// Create the OpenGL context +//======================================================================== + +#define setGLXattrib( attribs, index, attribName, attribValue ) \ + attribs[index++] = attribName; \ + attribs[index++] = attribValue; + +static int createContext( const _GLFWwndconfig *wndconfig, GLXFBConfigID fbconfigID ) +{ + int attribs[40]; + int flags, dummy, index; + GLXFBConfig *fbconfig; + + // Retrieve the previously selected GLXFBConfig + { + index = 0; + + setGLXattrib( attribs, index, GLX_FBCONFIG_ID, (int) fbconfigID ); + setGLXattrib( attribs, index, None, None ); + + if( _glfwWin.has_GLX_SGIX_fbconfig ) + { + fbconfig = _glfwWin.ChooseFBConfigSGIX( _glfwLibrary.display, + _glfwWin.screen, + attribs, + &dummy ); + } + else + { + fbconfig = glXChooseFBConfig( _glfwLibrary.display, + _glfwWin.screen, + attribs, + &dummy ); + } + + if( fbconfig == NULL ) + { + fprintf(stderr, "Unable to retrieve the selected GLXFBConfig\n"); + return GL_FALSE; + } + } + + // Retrieve the corresponding visual + if( _glfwWin.has_GLX_SGIX_fbconfig ) + { + _glfwWin.visual = _glfwWin.GetVisualFromFBConfigSGIX( _glfwLibrary.display, + *fbconfig ); + } + else + { + _glfwWin.visual = glXGetVisualFromFBConfig( _glfwLibrary.display, *fbconfig ); + } + + if( _glfwWin.visual == NULL ) + { + XFree( fbconfig ); + + fprintf(stderr, "Unable to retrieve visual for GLXFBconfig\n"); + return GL_FALSE; + } + + if( _glfwWin.has_GLX_ARB_create_context ) + { + index = 0; + + if( wndconfig->glMajor != 1 || wndconfig->glMinor != 0 ) + { + // Request an explicitly versioned context + + setGLXattrib( attribs, index, GLX_CONTEXT_MAJOR_VERSION_ARB, wndconfig->glMajor ); + setGLXattrib( attribs, index, GLX_CONTEXT_MINOR_VERSION_ARB, wndconfig->glMinor ); + } + + if( wndconfig->glForward || wndconfig->glDebug ) + { + flags = 0; + + if( wndconfig->glForward ) + { + flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + } + + if( wndconfig->glDebug ) + { + flags |= GLX_CONTEXT_DEBUG_BIT_ARB; + } + + setGLXattrib( attribs, index, GLX_CONTEXT_FLAGS_ARB, flags ); + } + + if( wndconfig->glProfile ) + { + if( !_glfwWin.has_GLX_ARB_create_context_profile ) + { + fprintf( stderr, "OpenGL profile requested but GLX_ARB_create_context_profile " + "is unavailable\n" ); + return GL_FALSE; + } + + if( wndconfig->glProfile == GLFW_OPENGL_CORE_PROFILE ) + { + flags = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; + } + else + { + flags = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + } + + setGLXattrib( attribs, index, GLX_CONTEXT_PROFILE_MASK_ARB, flags ); + } + + setGLXattrib( attribs, index, None, None ); + + _glfwWin.context = _glfwWin.CreateContextAttribsARB( _glfwLibrary.display, + *fbconfig, + NULL, + True, + attribs ); + } + else + { + if( _glfwWin.has_GLX_SGIX_fbconfig ) + { + _glfwWin.context = _glfwWin.CreateContextWithConfigSGIX( _glfwLibrary.display, + *fbconfig, + GLX_RGBA_TYPE, + NULL, + True ); + } + else + { + _glfwWin.context = glXCreateNewContext( _glfwLibrary.display, + *fbconfig, + GLX_RGBA_TYPE, + NULL, + True ); + } + } + + XFree( fbconfig ); + + if( _glfwWin.context == NULL ) + { + fprintf(stderr, "Unable to create OpenGL context\n"); + return GL_FALSE; + } + + _glfwWin.fbconfigID = fbconfigID; + + return GL_TRUE; +} + +#undef setGLXattrib + + +//======================================================================== +// Initialize GLX-specific extensions +//======================================================================== + +static void initGLXExtensions( void ) +{ + // This needs to include every function pointer loaded below + _glfwWin.SwapIntervalSGI = NULL; + _glfwWin.GetFBConfigAttribSGIX = NULL; + _glfwWin.ChooseFBConfigSGIX = NULL; + _glfwWin.CreateContextWithConfigSGIX = NULL; + _glfwWin.GetVisualFromFBConfigSGIX = NULL; + _glfwWin.CreateContextAttribsARB = NULL; + + // This needs to include every extension used below + _glfwWin.has_GLX_SGIX_fbconfig = GL_FALSE; + _glfwWin.has_GLX_SGI_swap_control = GL_FALSE; + _glfwWin.has_GLX_ARB_multisample = GL_FALSE; + _glfwWin.has_GLX_ARB_create_context = GL_FALSE; + _glfwWin.has_GLX_ARB_create_context_profile = GL_FALSE; + + if( _glfwPlatformExtensionSupported( "GLX_SGI_swap_control" ) ) + { + _glfwWin.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) + _glfwPlatformGetProcAddress( "glXSwapIntervalSGI" ); + + if( _glfwWin.SwapIntervalSGI ) + { + _glfwWin.has_GLX_SGI_swap_control = GL_TRUE; + } + } + + if( _glfwPlatformExtensionSupported( "GLX_SGIX_fbconfig" ) ) + { + _glfwWin.GetFBConfigAttribSGIX = (PFNGLXGETFBCONFIGATTRIBSGIXPROC) + _glfwPlatformGetProcAddress( "glXGetFBConfigAttribSGIX" ); + _glfwWin.ChooseFBConfigSGIX = (PFNGLXCHOOSEFBCONFIGSGIXPROC) + _glfwPlatformGetProcAddress( "glXChooseFBConfigSGIX" ); + _glfwWin.CreateContextWithConfigSGIX = (PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) + _glfwPlatformGetProcAddress( "glXCreateContextWithConfigSGIX" ); + _glfwWin.GetVisualFromFBConfigSGIX = (PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) + _glfwPlatformGetProcAddress( "glXGetVisualFromFBConfigSGIX" ); + + if( _glfwWin.GetFBConfigAttribSGIX && + _glfwWin.ChooseFBConfigSGIX && + _glfwWin.CreateContextWithConfigSGIX && + _glfwWin.GetVisualFromFBConfigSGIX ) + { + _glfwWin.has_GLX_SGIX_fbconfig = GL_TRUE; + } + } + + if( _glfwPlatformExtensionSupported( "GLX_ARB_multisample" ) ) + { + _glfwWin.has_GLX_ARB_multisample = GL_TRUE; + } + + if( _glfwPlatformExtensionSupported( "GLX_ARB_create_context" ) ) + { + _glfwWin.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) + _glfwPlatformGetProcAddress( "glXCreateContextAttribsARB" ); + + if( _glfwWin.CreateContextAttribsARB ) + { + _glfwWin.has_GLX_ARB_create_context = GL_TRUE; + } + } + + if( _glfwPlatformExtensionSupported( "GLX_ARB_create_context_profile" ) ) + { + _glfwWin.has_GLX_ARB_create_context_profile = GL_TRUE; + } +} + + +//======================================================================== +// Create the X11 window (and its colormap) +//======================================================================== + +static GLboolean createWindow( int width, int height, + const _GLFWwndconfig *wndconfig ) +{ + XEvent event; + unsigned long wamask; + XSetWindowAttributes wa; + + // Every window needs a colormap + // Create one based on the visual used by the current context + + _glfwWin.colormap = XCreateColormap( _glfwLibrary.display, + _glfwWin.root, + _glfwWin.visual->visual, + AllocNone ); + + // Create the actual window + { + wamask = CWBorderPixel | CWColormap | CWEventMask; + + wa.colormap = _glfwWin.colormap; + wa.border_pixel = 0; + wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | + PointerMotionMask | ButtonPressMask | ButtonReleaseMask | + ExposureMask | FocusChangeMask | VisibilityChangeMask; + + if( wndconfig->mode == GLFW_WINDOW ) + { + // The /only/ reason we are setting the background pixel here is + // that otherwise our window wont get any decorations on systems + // using Compiz on Intel hardware + wa.background_pixel = BlackPixel( _glfwLibrary.display, _glfwWin.screen ); + wamask |= CWBackPixel; + } + + _glfwWin.window = XCreateWindow( + _glfwLibrary.display, + _glfwWin.root, + 0, 0, // Upper left corner of this window on root + _glfwWin.width, _glfwWin.height, + 0, // Border width + _glfwWin.visual->depth, // Color depth + InputOutput, + _glfwWin.visual->visual, + wamask, + &wa + ); + if( !_glfwWin.window ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + } + + // Check whether an EWMH-compliant window manager is running + _glfwWin.hasEWMH = checkForEWMH(); + + if( _glfwWin.fullscreen && !_glfwWin.hasEWMH ) + { + // This is the butcher's way of removing window decorations + // Setting the override-redirect attribute on a window makes the window + // manager ignore the window completely (ICCCM, section 4) + // The good thing is that this makes undecorated fullscreen windows + // easy to do; the bad thing is that we have to do everything manually + // and some things (like iconify/restore) won't work at all, as they're + // usually performed by the window manager + + XSetWindowAttributes attributes; + attributes.override_redirect = True; + XChangeWindowAttributes( _glfwLibrary.display, + _glfwWin.window, + CWOverrideRedirect, + &attributes ); + + _glfwWin.overrideRedirect = GL_TRUE; + } + + // Find or create the protocol atom for window close notifications + _glfwWin.wmDeleteWindow = XInternAtom( _glfwLibrary.display, + "WM_DELETE_WINDOW", + False ); + + // Declare the WM protocols we support + { + int count = 0; + Atom protocols[2]; + + // The WM_DELETE_WINDOW ICCCM protocol + // Basic window close notification protocol + if( _glfwWin.wmDeleteWindow != None ) + { + protocols[count++] = _glfwWin.wmDeleteWindow; + } + + // The _NET_WM_PING EWMH protocol + // Tells the WM to ping our window and flag us as unresponsive if we + // don't reply within a few seconds + if( _glfwWin.wmPing != None ) + { + protocols[count++] = _glfwWin.wmPing; + } + + if( count > 0 ) + { + XSetWMProtocols( _glfwLibrary.display, _glfwWin.window, + protocols, count ); + } + } + + // Set ICCCM WM_HINTS property + { + XWMHints *hints = XAllocWMHints(); + if( !hints ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + hints->flags = StateHint; + hints->initial_state = NormalState; + + XSetWMHints( _glfwLibrary.display, _glfwWin.window, hints ); + XFree( hints ); + } + + // Set ICCCM WM_NORMAL_HINTS property (even if no parts are set) + { + XSizeHints *hints = XAllocSizeHints(); + if( !hints ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + hints->flags = 0; + + if( wndconfig->windowNoResize ) + { + hints->flags |= (PMinSize | PMaxSize); + hints->min_width = hints->max_width = _glfwWin.width; + hints->min_height = hints->max_height = _glfwWin.height; + } + + XSetWMNormalHints( _glfwLibrary.display, _glfwWin.window, hints ); + XFree( hints ); + } + + _glfwPlatformSetWindowTitle( "GLFW Window" ); + + // Make sure the window is mapped before proceeding + XMapWindow( _glfwLibrary.display, _glfwWin.window ); + XPeekIfEvent( _glfwLibrary.display, &event, isMapNotify, + (char*)_glfwWin.window ); + + return GL_TRUE; +} + + +//======================================================================== +// Enter fullscreen mode +//======================================================================== + +static void enterFullscreenMode( void ) +{ + if( !_glfwWin.Saver.changed ) + { + // Remember old screen saver settings + XGetScreenSaver( _glfwLibrary.display, + &_glfwWin.Saver.timeout, &_glfwWin.Saver.interval, + &_glfwWin.Saver.blanking, &_glfwWin.Saver.exposure ); + + // Disable screen saver + XSetScreenSaver( _glfwLibrary.display, 0, 0, DontPreferBlanking, + DefaultExposures ); + + _glfwWin.Saver.changed = GL_TRUE; + } + + _glfwSetVideoMode( _glfwWin.screen, + &_glfwWin.width, &_glfwWin.height, + &_glfwWin.refreshRate ); + + if( _glfwWin.hasEWMH && + _glfwWin.wmState != None && + _glfwWin.wmStateFullscreen != None ) + { + if( _glfwWin.wmActiveWindow != None ) + { + // Ask the window manager to raise and focus the GLFW window + // Only focused windows with the _NET_WM_STATE_FULLSCREEN state end + // up on top of all other windows ("Stacking order" in EWMH spec) + + XEvent event; + memset( &event, 0, sizeof(event) ); + + event.type = ClientMessage; + event.xclient.window = _glfwWin.window; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = _glfwWin.wmActiveWindow; + event.xclient.data.l[0] = 1; // Sender is a normal application + event.xclient.data.l[1] = 0; // We don't really know the timestamp + + XSendEvent( _glfwLibrary.display, + _glfwWin.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event ); + } + + // Ask the window manager to make the GLFW window a fullscreen window + // Fullscreen windows are undecorated and, when focused, are kept + // on top of all other windows + + XEvent event; + memset( &event, 0, sizeof(event) ); + + event.type = ClientMessage; + event.xclient.window = _glfwWin.window; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = _glfwWin.wmState; + event.xclient.data.l[0] = _NET_WM_STATE_ADD; + event.xclient.data.l[1] = _glfwWin.wmStateFullscreen; + event.xclient.data.l[2] = 0; // No secondary property + event.xclient.data.l[3] = 1; // Sender is a normal application + + XSendEvent( _glfwLibrary.display, + _glfwWin.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event ); + } + else if( _glfwWin.overrideRedirect ) + { + // In override-redirect mode, we have divorced ourselves from the + // window manager, so we need to do everything manually + + XRaiseWindow( _glfwLibrary.display, _glfwWin.window ); + XSetInputFocus( _glfwLibrary.display, _glfwWin.window, + RevertToParent, CurrentTime ); + XMoveWindow( _glfwLibrary.display, _glfwWin.window, 0, 0 ); + XResizeWindow( _glfwLibrary.display, _glfwWin.window, + _glfwWin.width, _glfwWin.height ); + } + + if( _glfwWin.mouseLock ) + { + _glfwPlatformHideMouseCursor(); + } + + // HACK: Try to get window inside viewport (for virtual displays) by moving + // the mouse cursor to the upper left corner (and then to the center) + // This hack should be harmless on saner systems as well + XWarpPointer( _glfwLibrary.display, None, _glfwWin.window, 0,0,0,0, 0,0 ); + XWarpPointer( _glfwLibrary.display, None, _glfwWin.window, 0,0,0,0, + _glfwWin.width / 2, _glfwWin.height / 2 ); +} + +//======================================================================== +// Leave fullscreen mode +//======================================================================== + +static void leaveFullscreenMode( void ) +{ + _glfwRestoreVideoMode(); + + // Did we change the screen saver setting? + if( _glfwWin.Saver.changed ) + { + // Restore old screen saver settings + XSetScreenSaver( _glfwLibrary.display, + _glfwWin.Saver.timeout, + _glfwWin.Saver.interval, + _glfwWin.Saver.blanking, + _glfwWin.Saver.exposure ); + + _glfwWin.Saver.changed = GL_FALSE; + } + + if( _glfwWin.hasEWMH && + _glfwWin.wmState != None && + _glfwWin.wmStateFullscreen != None ) + { + // Ask the window manager to make the GLFW window a normal window + // Normal windows usually have frames and other decorations + + XEvent event; + memset( &event, 0, sizeof(event) ); + + event.type = ClientMessage; + event.xclient.window = _glfwWin.window; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = _glfwWin.wmState; + event.xclient.data.l[0] = _NET_WM_STATE_REMOVE; + event.xclient.data.l[1] = _glfwWin.wmStateFullscreen; + event.xclient.data.l[2] = 0; // No secondary property + event.xclient.data.l[3] = 1; // Sender is a normal application + + XSendEvent( _glfwLibrary.display, + _glfwWin.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event ); + } + + if( _glfwWin.mouseLock ) + { + _glfwPlatformShowMouseCursor(); + } +} + +//======================================================================== +// Get and process next X event (called by _glfwPlatformPollEvents) +// Returns GL_TRUE if a window close request was received +//======================================================================== + +static GLboolean processSingleEvent( void ) +{ + XEvent event; + XNextEvent( _glfwLibrary.display, &event ); + + switch( event.type ) + { + case KeyPress: + { + // A keyboard key was pressed + + // Translate and report key press + _glfwInputKey( translateKey( event.xkey.keycode ), GLFW_PRESS ); + + // Translate and report character input + if( _glfwWin.charCallback ) + { + _glfwInputChar( translateChar( &event.xkey ), GLFW_PRESS ); + } + break; + } + + case KeyRelease: + { + // A keyboard key was released + + // Do not report key releases for key repeats. For key repeats we + // will get KeyRelease/KeyPress pairs with similar or identical + // time stamps. User selected key repeat filtering is handled in + // _glfwInputKey()/_glfwInputChar(). + if( XEventsQueued( _glfwLibrary.display, QueuedAfterReading ) ) + { + XEvent nextEvent; + XPeekEvent( _glfwLibrary.display, &nextEvent ); + + if( nextEvent.type == KeyPress && + nextEvent.xkey.window == event.xkey.window && + nextEvent.xkey.keycode == event.xkey.keycode ) + { + // This last check is a hack to work around key repeats + // leaking through due to some sort of time drift + // Toshiyuki Takahashi can press a button 16 times per + // second so it's fairly safe to assume that no human is + // pressing the key 50 times per second (value is ms) + if( ( nextEvent.xkey.time - event.xkey.time ) < 20 ) + { + // Do not report anything for this event + break; + } + } + } + + // Translate and report key release + _glfwInputKey( translateKey( event.xkey.keycode ), GLFW_RELEASE ); + + // Translate and report character input + if( _glfwWin.charCallback ) + { + _glfwInputChar( translateChar( &event.xkey ), GLFW_RELEASE ); + } + break; + } + + case ButtonPress: + { + // A mouse button was pressed or a scrolling event occurred + + if( event.xbutton.button == Button1 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS ); + } + else if( event.xbutton.button == Button2 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS ); + } + else if( event.xbutton.button == Button3 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS ); + } + + // XFree86 3.3.2 and later translates mouse wheel up/down into + // mouse button 4 & 5 presses + else if( event.xbutton.button == Button4 ) + { + _glfwInput.WheelPos++; // To verify: is this up or down? + if( _glfwWin.mouseWheelCallback ) + { + _glfwWin.mouseWheelCallback( _glfwInput.WheelPos ); + } + } + else if( event.xbutton.button == Button5 ) + { + _glfwInput.WheelPos--; + if( _glfwWin.mouseWheelCallback ) + { + _glfwWin.mouseWheelCallback( _glfwInput.WheelPos ); + } + } + break; + } + + case ButtonRelease: + { + // A mouse button was released + + if( event.xbutton.button == Button1 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_LEFT, + GLFW_RELEASE ); + } + else if( event.xbutton.button == Button2 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_MIDDLE, + GLFW_RELEASE ); + } + else if( event.xbutton.button == Button3 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_RIGHT, + GLFW_RELEASE ); + } + break; + } + + case MotionNotify: + { + // The mouse cursor was moved + + if( event.xmotion.x != _glfwInput.CursorPosX || + event.xmotion.y != _glfwInput.CursorPosY ) + { + // The mouse cursor was moved and we didn't do it + + if( _glfwWin.mouseLock ) + { + if( _glfwWin.pointerHidden ) + { + _glfwInput.MousePosX += event.xmotion.x - + _glfwInput.CursorPosX; + _glfwInput.MousePosY += event.xmotion.y - + _glfwInput.CursorPosY; + } + } + else + { + _glfwInput.MousePosX = event.xmotion.x; + _glfwInput.MousePosY = event.xmotion.y; + } + + _glfwInput.CursorPosX = event.xmotion.x; + _glfwInput.CursorPosY = event.xmotion.y; + _glfwInput.MouseMoved = GL_TRUE; + + if( _glfwWin.mousePosCallback ) + { + _glfwWin.mousePosCallback( _glfwInput.MousePosX, + _glfwInput.MousePosY ); + } + } + break; + } + + case ConfigureNotify: + { + if( event.xconfigure.width != _glfwWin.width || + event.xconfigure.height != _glfwWin.height ) + { + // The window was resized + + _glfwWin.width = event.xconfigure.width; + _glfwWin.height = event.xconfigure.height; + if( _glfwWin.windowSizeCallback ) + { + _glfwWin.windowSizeCallback( _glfwWin.width, + _glfwWin.height ); + } + } + break; + } + + case ClientMessage: + { + if( (Atom) event.xclient.data.l[ 0 ] == _glfwWin.wmDeleteWindow ) + { + // The window manager was asked to close the window, for example by + // the user pressing a 'close' window decoration button + + return GL_TRUE; + } + else if( _glfwWin.wmPing != None && + (Atom) event.xclient.data.l[ 0 ] == _glfwWin.wmPing ) + { + // The window manager is pinging us to make sure we are still + // responding to events + + event.xclient.window = _glfwWin.root; + XSendEvent( _glfwLibrary.display, + event.xclient.window, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event ); + } + + break; + } + + case MapNotify: + { + // The window was mapped + + _glfwWin.iconified = GL_FALSE; + break; + } + + case UnmapNotify: + { + // The window was unmapped + + _glfwWin.iconified = GL_TRUE; + break; + } + + case FocusIn: + { + // The window gained focus + + _glfwWin.active = GL_TRUE; + + if( _glfwWin.mouseLock ) + { + _glfwPlatformHideMouseCursor(); + } + + break; + } + + case FocusOut: + { + // The window lost focus + + _glfwWin.active = GL_FALSE; + _glfwInputDeactivation(); + + if( _glfwWin.mouseLock ) + { + _glfwPlatformShowMouseCursor(); + } + + break; + } + + case Expose: + { + // The window's contents was damaged + + if( _glfwWin.windowRefreshCallback ) + { + _glfwWin.windowRefreshCallback(); + } + break; + } + + // Was the window destroyed? + case DestroyNotify: + return GL_FALSE; + + default: + { +#if defined( _GLFW_HAS_XRANDR ) + switch( event.type - _glfwLibrary.XRandR.eventBase ) + { + case RRScreenChangeNotify: + { + // Show XRandR that we really care + XRRUpdateConfiguration( &event ); + break; + } + } +#endif + break; + } + } + + // The window was not destroyed + return GL_FALSE; +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Here is where the window is created, and +// the OpenGL rendering context is created +//======================================================================== + +int _glfwPlatformOpenWindow( int width, int height, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig ) +{ + _GLFWfbconfig closest; + + // Clear platform specific GLFW window state + _glfwWin.visual = (XVisualInfo*)NULL; + _glfwWin.colormap = (Colormap)0; + _glfwWin.context = (GLXContext)NULL; + _glfwWin.window = (Window)0; + _glfwWin.pointerGrabbed = GL_FALSE; + _glfwWin.pointerHidden = GL_FALSE; + _glfwWin.keyboardGrabbed = GL_FALSE; + _glfwWin.overrideRedirect = GL_FALSE; + _glfwWin.FS.modeChanged = GL_FALSE; + _glfwWin.Saver.changed = GL_FALSE; + _glfwWin.refreshRate = wndconfig->refreshRate; + _glfwWin.windowNoResize = wndconfig->windowNoResize; + + _glfwWin.wmDeleteWindow = None; + _glfwWin.wmPing = None; + _glfwWin.wmState = None; + _glfwWin.wmStateFullscreen = None; + _glfwWin.wmActiveWindow = None; + + // As the 2.x API doesn't understand multiple display devices, we hardcode + // this choice and hope for the best + _glfwWin.screen = DefaultScreen( _glfwLibrary.display ); + _glfwWin.root = RootWindow( _glfwLibrary.display, _glfwWin.screen ); + + // Create the invisible cursor for hidden cursor mode + _glfwWin.cursor = createNULLCursor( _glfwLibrary.display, _glfwWin.root ); + + initGLXExtensions(); + + // Choose the best available fbconfig + { + unsigned int fbcount; + _GLFWfbconfig *fbconfigs; + const _GLFWfbconfig *result; + + fbconfigs = getFBConfigs( &fbcount ); + if( !fbconfigs ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + result = _glfwChooseFBConfig( fbconfig, fbconfigs, fbcount ); + if( !result ) + { + free( fbconfigs ); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + closest = *result; + free( fbconfigs ); + } + + if( !createContext( wndconfig, (GLXFBConfigID) closest.platformID ) ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + if( !createWindow( width, height, wndconfig ) ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + if( wndconfig->mode == GLFW_FULLSCREEN ) + { +#if defined( _GLFW_HAS_XRANDR ) + // Request screen change notifications + if( _glfwLibrary.XRandR.available ) + { + XRRSelectInput( _glfwLibrary.display, + _glfwWin.window, + RRScreenChangeNotifyMask ); + } +#endif + enterFullscreenMode(); + } + + // Process the window map event and any other that may have arrived + _glfwPlatformPollEvents(); + + // Retrieve and set initial cursor position + { + Window window, root; + int windowX, windowY, rootX, rootY; + unsigned int mask; + + XQueryPointer( _glfwLibrary.display, + _glfwWin.window, + &root, + &window, + &rootX, &rootY, + &windowX, &windowY, + &mask ); + + // TODO: Probably check for some corner cases here. + + _glfwInput.MousePosX = windowX; + _glfwInput.MousePosY = windowY; + } + + // Connect the context to the window + glXMakeCurrent( _glfwLibrary.display, _glfwWin.window, _glfwWin.context ); + + return GL_TRUE; +} + + +//======================================================================== +// Properly kill the window/video display +//======================================================================== + +void _glfwPlatformCloseWindow( void ) +{ + if( _glfwWin.fullscreen ) + { + leaveFullscreenMode(); + } + + if( _glfwWin.context ) + { + // Release and destroy the context + glXMakeCurrent( _glfwLibrary.display, None, NULL ); + glXDestroyContext( _glfwLibrary.display, _glfwWin.context ); + _glfwWin.context = NULL; + } + + if( _glfwWin.visual ) + { + XFree( _glfwWin.visual ); + _glfwWin.visual = NULL; + } + + if( _glfwWin.window ) + { + XUnmapWindow( _glfwLibrary.display, _glfwWin.window ); + XDestroyWindow( _glfwLibrary.display, _glfwWin.window ); + _glfwWin.window = (Window) 0; + } + + if( _glfwWin.colormap ) + { + XFreeColormap( _glfwLibrary.display, _glfwWin.colormap ); + _glfwWin.colormap = (Colormap) 0; + } + + if( _glfwWin.cursor ) + { + XFreeCursor( _glfwLibrary.display, _glfwWin.cursor ); + _glfwWin.cursor = (Cursor) 0; + } +} + + +//======================================================================== +// Set the window title +//======================================================================== + +void _glfwPlatformSetWindowTitle( const char *title ) +{ + // Set window & icon title + XStoreName( _glfwLibrary.display, _glfwWin.window, title ); + XSetIconName( _glfwLibrary.display, _glfwWin.window, title ); +} + + +//======================================================================== +// Set the window size +//======================================================================== + +void _glfwPlatformSetWindowSize( int width, int height ) +{ + int mode = 0, rate, sizeChanged = GL_FALSE; + XSizeHints *sizehints; + + rate = _glfwWin.refreshRate; + + if( _glfwWin.fullscreen ) + { + // Get the closest matching video mode for the specified window size + mode = _glfwGetClosestVideoMode( _glfwWin.screen, &width, &height, &rate ); + } + + if( _glfwWin.windowNoResize ) + { + // Update window size restrictions to match new window size + + sizehints = XAllocSizeHints(); + sizehints->flags = 0; + + sizehints->min_width = sizehints->max_width = width; + sizehints->min_height = sizehints->max_height = height; + + XSetWMNormalHints( _glfwLibrary.display, _glfwWin.window, sizehints ); + XFree( sizehints ); + } + + // Change window size before changing fullscreen mode? + if( _glfwWin.fullscreen && (width > _glfwWin.width) ) + { + XResizeWindow( _glfwLibrary.display, _glfwWin.window, width, height ); + sizeChanged = GL_TRUE; + } + + if( _glfwWin.fullscreen ) + { + // Change video mode, keeping current refresh rate + _glfwSetVideoModeMODE( _glfwWin.screen, mode, _glfwWin.refreshRate ); + } + + // Set window size (if not already changed) + if( !sizeChanged ) + { + XResizeWindow( _glfwLibrary.display, _glfwWin.window, width, height ); + } +} + + +//======================================================================== +// Set the window position. +//======================================================================== + +void _glfwPlatformSetWindowPos( int x, int y ) +{ + XMoveWindow( _glfwLibrary.display, _glfwWin.window, x, y ); +} + + +//======================================================================== +// Window iconification +//======================================================================== + +void _glfwPlatformIconifyWindow( void ) +{ + if( _glfwWin.overrideRedirect ) + { + // We can't iconify/restore override-redirect windows, as that's + // performed by the window manager + return; + } + + XIconifyWindow( _glfwLibrary.display, _glfwWin.window, _glfwWin.screen ); +} + + +//======================================================================== +// Window un-iconification +//======================================================================== + +void _glfwPlatformRestoreWindow( void ) +{ + if( _glfwWin.overrideRedirect ) + { + // We can't iconify/restore override-redirect windows, as that's + // performed by the window manager + return; + } + + XMapWindow( _glfwLibrary.display, _glfwWin.window ); +} + + +//======================================================================== +// Swap OpenGL buffers and poll any new events +//======================================================================== + +void _glfwPlatformSwapBuffers( void ) +{ + // Update display-buffer + glXSwapBuffers( _glfwLibrary.display, _glfwWin.window ); +} + + +//======================================================================== +// Set double buffering swap interval +//======================================================================== + +void _glfwPlatformSwapInterval( int interval ) +{ + if( _glfwWin.has_GLX_SGI_swap_control ) + { + _glfwWin.SwapIntervalSGI( interval ); + } +} + + +//======================================================================== +// Read back framebuffer parameters from the context +//======================================================================== + +void _glfwPlatformRefreshWindowParams( void ) +{ + int dummy; + GLXFBConfig *fbconfig; +#if defined( _GLFW_HAS_XRANDR ) + XRRScreenConfiguration *sc; +#elif defined( _GLFW_HAS_XF86VIDMODE ) + XF86VidModeModeLine modeline; + int dotclock; + float pixels_per_second, pixels_per_frame; +#endif + int attribs[] = { GLX_FBCONFIG_ID, _glfwWin.fbconfigID, None }; + + if( _glfwWin.has_GLX_SGIX_fbconfig ) + { + fbconfig = _glfwWin.ChooseFBConfigSGIX( _glfwLibrary.display, + _glfwWin.screen, + attribs, + &dummy ); + } + else + { + fbconfig = glXChooseFBConfig( _glfwLibrary.display, + _glfwWin.screen, + attribs, + &dummy ); + } + + if( fbconfig == NULL ) + { + // This should never ever happen + // TODO: Figure out what to do when this happens + fprintf( stderr, "Cannot find known GLXFBConfig by ID. " + "This cannot happen. Have a nice day.\n"); + abort(); + } + + // There is no clear definition of an "accelerated" context on X11/GLX, and + // true sounds better than false, so we hardcode true here + _glfwWin.accelerated = GL_TRUE; + + _glfwWin.redBits = getFBConfigAttrib( *fbconfig, GLX_RED_SIZE ); + _glfwWin.greenBits = getFBConfigAttrib( *fbconfig, GLX_GREEN_SIZE ); + _glfwWin.blueBits = getFBConfigAttrib( *fbconfig, GLX_BLUE_SIZE ); + + _glfwWin.alphaBits = getFBConfigAttrib( *fbconfig, GLX_ALPHA_SIZE ); + _glfwWin.depthBits = getFBConfigAttrib( *fbconfig, GLX_DEPTH_SIZE ); + _glfwWin.stencilBits = getFBConfigAttrib( *fbconfig, GLX_STENCIL_SIZE ); + + _glfwWin.accumRedBits = getFBConfigAttrib( *fbconfig, GLX_ACCUM_RED_SIZE ); + _glfwWin.accumGreenBits = getFBConfigAttrib( *fbconfig, GLX_ACCUM_GREEN_SIZE ); + _glfwWin.accumBlueBits = getFBConfigAttrib( *fbconfig, GLX_ACCUM_BLUE_SIZE ); + _glfwWin.accumAlphaBits = getFBConfigAttrib( *fbconfig, GLX_ACCUM_ALPHA_SIZE ); + + _glfwWin.auxBuffers = getFBConfigAttrib( *fbconfig, GLX_AUX_BUFFERS ); + _glfwWin.stereo = getFBConfigAttrib( *fbconfig, GLX_STEREO ) ? 1 : 0; + + // Get FSAA buffer sample count + if( _glfwWin.has_GLX_ARB_multisample ) + { + _glfwWin.samples = getFBConfigAttrib( *fbconfig, GLX_SAMPLES ); + } + else + { + _glfwWin.samples = 0; + } + + // Default to refresh rate unknown (=0 according to GLFW spec) + _glfwWin.refreshRate = 0; + + // Retrieve refresh rate if possible +#if defined( _GLFW_HAS_XRANDR ) + if( _glfwLibrary.XRandR.available ) + { + sc = XRRGetScreenInfo( _glfwLibrary.display, _glfwWin.root ); + _glfwWin.refreshRate = XRRConfigCurrentRate( sc ); + XRRFreeScreenConfigInfo( sc ); + } +#elif defined( _GLFW_HAS_XF86VIDMODE ) + if( _glfwLibrary.XF86VidMode.available ) + { + // Use the XF86VidMode extension to get current video mode + XF86VidModeGetModeLine( _glfwLibrary.display, _glfwWin.screen, + &dotclock, &modeline ); + pixels_per_second = 1000.0f * (float) dotclock; + pixels_per_frame = (float) modeline.htotal * modeline.vtotal; + _glfwWin.refreshRate = (int)(pixels_per_second/pixels_per_frame+0.5); + } +#endif + + XFree( fbconfig ); +} + + +//======================================================================== +// Poll for new window and input events +//======================================================================== + +void _glfwPlatformPollEvents( void ) +{ + GLboolean closeRequested = GL_FALSE; + + // Flag that the cursor has not moved + _glfwInput.MouseMoved = GL_FALSE; + + // Process all pending events + while( XPending( _glfwLibrary.display ) ) + { + if( processSingleEvent() ) + { + closeRequested = GL_TRUE; + } + } + + // Did we get mouse movement in fully enabled hidden cursor mode? + if( _glfwInput.MouseMoved && _glfwWin.pointerHidden ) + { + _glfwPlatformSetMouseCursorPos( _glfwWin.width/2, + _glfwWin.height/2 ); + } + + if( closeRequested && _glfwWin.windowCloseCallback ) + { + closeRequested = _glfwWin.windowCloseCallback(); + } + if( closeRequested ) + { + glfwCloseWindow(); + } +} + + +//======================================================================== +// Wait for new window and input events +//======================================================================== + +void _glfwPlatformWaitEvents( void ) +{ + XEvent event; + + // Block waiting for an event to arrive + XNextEvent( _glfwLibrary.display, &event ); + XPutBackEvent( _glfwLibrary.display, &event ); + + _glfwPlatformPollEvents(); +} + + +//======================================================================== +// Hide mouse cursor (lock it) +//======================================================================== + +void _glfwPlatformHideMouseCursor( void ) +{ + // Hide cursor + if( !_glfwWin.pointerHidden ) + { + XDefineCursor( _glfwLibrary.display, _glfwWin.window, _glfwWin.cursor ); + _glfwWin.pointerHidden = GL_TRUE; + } + + // Grab cursor to user window + if( !_glfwWin.pointerGrabbed ) + { + if( XGrabPointer( _glfwLibrary.display, _glfwWin.window, True, + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask, GrabModeAsync, GrabModeAsync, + _glfwWin.window, None, CurrentTime ) == + GrabSuccess ) + { + _glfwWin.pointerGrabbed = GL_TRUE; + } + } +} + + +//======================================================================== +// Show mouse cursor (unlock it) +//======================================================================== + +void _glfwPlatformShowMouseCursor( void ) +{ + // Un-grab cursor (only in windowed mode: in fullscreen mode we still + // want the mouse grabbed in order to confine the cursor to the window + // area) + if( _glfwWin.pointerGrabbed ) + { + XUngrabPointer( _glfwLibrary.display, CurrentTime ); + _glfwWin.pointerGrabbed = GL_FALSE; + } + + // Show cursor + if( _glfwWin.pointerHidden ) + { + XUndefineCursor( _glfwLibrary.display, _glfwWin.window ); + _glfwWin.pointerHidden = GL_FALSE; + } +} + + +//======================================================================== +// Set physical mouse cursor position +//======================================================================== + +void _glfwPlatformSetMouseCursorPos( int x, int y ) +{ + // Store the new position so we can recognise it later + _glfwInput.CursorPosX = x; + _glfwInput.CursorPosY = y; + + XWarpPointer( _glfwLibrary.display, None, _glfwWin.window, 0,0,0,0, x, y ); +} + diff --git a/readme.html b/readme.html new file mode 100644 index 00000000..e304949d --- /dev/null +++ b/readme.html @@ -0,0 +1,821 @@ + + + + + + GLFW Readme File + + + + + +

GLFW 2.7 Lite

+ +
    +
  1. Introduction
  2. +
  3. Compiling GLFW and the example programs
  4. +
  5. Installing GLFW
  6. +
  7. Using GLFW
  8. +
  9. Frequently Asked Questions
  10. +
  11. Version history
  12. +
  13. Directory structure of the GLFW distribution
  14. +
  15. Contacting the project
  16. +
  17. Acknowledgements
  18. +
+ + +

1. Introduction

+ +

Welcome to version 2.7 Lite of the GLFW OpenGL framework. GLFW is +a free, open source, portable framework for OpenGL application development. In +short, it is a library that constitutes a powerful API for handling operating +system specific tasks, such as opening an OpenGL window, reading keyboard and +mouse input, and more.

+ +

Please note that this is the Lite version of GLFW, which +means that some areas of functionality present in 2.x mainline versions of GLFW +have been removed.

+ +
+

2. Compiling GLFW and the example programs

+ +

To compile GLFW and the accompanying example programs, you will need the CMake build system.

+ + +

3. Installing GLFW

+ +

A rudimentary installation target is provided for all supported platforms +via the CMake build system.

+ +

For Unix-like platforms, the command is:

+ +

$ make install

+ +

Note that you may need to run this command as root or via +sudo(1) in order to install GLFW into the various system +directories.

+ +

For Visual C++ and other integrated development environments, an installation +target should appear in the by CMake generated project files.

+ +
+

4. Using GLFW

+ +

There are two aspects to using GLFW: + +

+

    +
  1. How the GLFW API works
  2. +
  3. How to compile programs that use GLFW
  4. +
+ +

The first point is covered in the GLFW +Users Guide and the GLFW Reference +Manual, and we suggest that you read at least the Users Guide, since +it's a good introduction to the GLFW API.

+ +

Designing and compiling programs that use GLFW is not very difficult. +A few rules for successfully designing GLFW-based programs are presented +in the following sections.

+ +

4.1 Include GL/glfw.h

+ +

In your program, you should include GL/glfw.h like this:

+ +

#include <GL/glfw.h>

+ +

This include file defines all the necessary constants, types and prototypes +that are used to interact with the GLFW API. It also includes +GL/gl.h and GL/glu.h, and - it defines all the +necessary constants and types that are necessary for OpenGL to work on +different platforms.

+ +

For instance, under Windows you are normally required to include +windows.h before you include GL/gl.h. If you write +such a program, it would not compile under e.g. Linux since +windows.h does not exist under Linux. GL/glfw.h +takes care of these things for you. Note however that it does not actually +include windows.h, it merely mimics the parts of it that are +needed for GL/gl.h and GL/glu.h (this way we do not +get the thousands of constants, types and prototypes that could otherwise +possibly interfere with our own declarations).

+ +

In other words: +

    +
  • Do not include GL/gl.h or GL/glu.h + (GLFW does it for you)
  • +
  • Do not include windows.h unless you need + to write Win32-specific code
  • +
  • If you do need to include windows.h, do it + before including GL/glfw.h.
  • +
+ +

4.2 Link with the correct libraries

+ +

4.2.1 Windows static library

+ +

If you link with the static version of GLFW, it is also necessary to +link with some system libraries that GLFW uses.

+ +

When linking a program under Windows that uses the static version of GLFW, +you must also link with the following libraries: opengl32, +user32 and kernel32. Some of these libraries may be +linked with by default by your compiler. In the table below you can see the +minimum required link options for each supported Windows compiler (you may want +to add other libraries as well, such as glu32):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CompilerLink options
Borland C++ Builderglfw.lib opengl32.lib
CygwinSee Unix static library below
LCC-Win32glfw.lib opengl32.lib
Microsoft Visual C++glfw.lib opengl32.lib user32.lib
MinGW32-lglfw -lopengl32
OpenWatcomglfw.lib opengl32.lib user32.lib
Pelles Cglfw.lib opengl32.lib user32.lib kernel32.lib
+ + +

4.2.2 Windows DLL

+ +

To compile a program that uses the DLL version of GLFW, you need to define +the GLFW_DLL constant. This can either be done with a compiler switch, +typically by adding -DGLFW_DLL to the list of compiler options. You can +also do it by adding the following line to all your source files that include +glfw.h, before including it:

+ +

#define GLFW_DLL

+ +

When linking a program under Windows that uses the DLL version of GLFW, +the only library you need to link with for GLFW to work is glfwdll. +In the table below you can see the minimum required link options for each +supported Windows compiler (you may want to add other libraries as well, +such as opengl32 and glu32):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CompilerLink options
Borland C++ Builderglfwdll.lib
Cygwin-lglfwdll
LCC-Win32glfwdll.lib
Microsoft Visual C++glfwdll.lib
MinGW32-lglfwdll
OpenWatcomglfwdll.lib
Pelles Cglfwdll.lib
+ +

4.2.3 Unix static library

+ +

GLFW now supports +pkgconfig, +and a libglfw.pc file is generated and installed when you install the library. +For systems that do not provide pkgconfig, you should look in this file for the +proper compile and link flags for your system, as determined by compile.sh at +compile time.

+ +

A typical compile and link command line may look like this (using GCC):

+ +

gcc `pkg-config --cflags libglfw` -o myprog myprog.c `pkg-config --libs libglfw`

+ +

If you use GLU functions in your program then you should also add the +-lGLU flag. + + +

4.2.5 Mac OS X static library

+ +

When compiling and linking a program under Mac OS X that uses GLFW, you +must also link with the following frameworks: Carbon.framework, +AGL.framework and OpenGL.framework. + +

If you are using Xcode, you simply add the GLFW library +libglfw.a and these frameworks to your project. If, however, you +are building your program from the command line, there are two methods for +correctly linking your GLFW program.

+ +

GLFW now supports pkgconfig, and a pkgconfig +file named libglfw.pc is generated and installed when you install the library. +You can find pkgconfig in most packaging systems, such as Fink and DarwinPorts, so if you have one +of them installed, simply install pkgconfig. Once you have pkgconfig available, +the command line for compiling and linking your program is:

+ +

gcc `pkg-config --cflags libglfw` -o myprog myprog.c `pkg-config --libs libglfw`

+ +

If you do not wish to use pkgconfig, you will need to add the required +frameworks and libraries to your command line using the -l and +-framework switches, i.e.:

+ +

gcc -o myprog myprog.c -lglfw -framework Carbon -framework AGL -framework OpenGL

+ +

Note that you do not add the .framework extension to a framework when adding +it from the command line.

+ +

These frameworks contain all GL and GLU functions, so there is no need to +add additional libraries or frameworks when using GLU functionality. Also note +that even though your machine may have Unix-style GL libraries, they are for +use with the X Window System, and will not work with the Mac OS X +native version of GLFW.

+ + +

9. Frequently Asked Questions

+ +
+

5. Version history

+ +

2.7 Lite

+
    +
  • Removed all threading support
  • +
  • Removed all image and texture loading support
  • +
  • Removed all build files not related to CMake
  • +
  • Removed D, Delphi and Lua bindings
  • +
  • Imported CMake work from pre-3.0 branch
  • +
+ +

2.7

+
    +
  • Added GLFW_OPENGL_VERSION_MAJOR, + GLFW_OPENGL_VERSION_MINOR and + GLFW_OPENGL_FORWARD_COMPAT hints for versioned context + creation support
  • +
  • Added GLFW_NO_GLU macro for disabling the inclusion of the + GLU header
  • +
  • Added the proper DEF file to the Visual C++ DLL project file
  • +
  • Added a rudimentary joystick API testing example
  • +
  • Changed all comments in public header file to plain C style
  • +
  • Removed all deprecated platforms
  • +
  • [X11] Added x11-distro-install install target, intended for packagers
  • +
  • [X11] Removed support for GLX version 1.3 and below
  • +
  • [X11] Bugfix: Misspelt struct member in XF86VidMode code path
  • +
  • [MacOSX] Bugfix: Key repeat events were ignored on 10.5 Leopard
  • +
  • [Win32] Bugfix: Improper use of wParam for WM_SYSCOMMAND
  • +
  • [Win32] Bugfix: Derivatives of stream.c not cleaned up by compile.bat
  • +
  • [Win32] Bugfix: Pointer for GetExtensionsStringARB was not initialized
  • +
  • [Win32] Bugfix: Updated API version in makefiles
  • +
+ +

2.6

+
+ +

2.5

+
    +
  • Added the function glfwWaitEvents
  • +
  • Added window close callback, which enables a program to prevent a user + from closing a window with the window manager
  • +
  • Added window refresh callback, which is called when the window needs + to be refreshed
  • +
  • Added support for loading alpha textures (GLFW_ALPHA_MAP_BIT)
  • +
  • Added support for the Lua programming language
  • +
  • Added support for the D programming language
  • +
  • Added support for the Pelles C compiler for Windows
  • +
  • Added API level support for up to eight mouse buttons
  • +
  • [Win32] Added support for up to five mouse buttons
  • +
  • [Win32] Mouse down events capture mouse input
  • +
  • [Win32] Bugfix: The DLL now exports glfwSetTime
  • +
  • [Win32] Fix: The GLFW window is now placed in the upper left corner + of the desktop working area
  • +
  • [Win32/X11] Bugfix: More robust check for SwapInterval
  • +
  • [X11] Added support for USB joysticks under Linux (/dev/input/js*)
  • +
  • [X11] Bugfix: Added support for GLX extensions in glfwExtensionSupported
  • +
  • [X11] Bugfix: More robust fullscreen mode (?)
  • +
  • [X11] Bugfix: Runtime check of XF86VidMode support for the active + display
  • +
  • [X11] Bugfix: Some mouse button events were reported incorrectly
  • +
  • [MacOSX] Added support for the input char callback.
  • +
  • [MacOSX] Added video mode validation and duplicate elimination.
  • +
  • [MacOSX] Switched to a new MakeBundle.sh script.
  • +
  • [MacOSX] Added emulation of the window refresh callback.
  • +
  • [MacOSX] Bugfix: The window and its associated resources are now + properly released.
  • +
  • [MacOSX] Bugfix: Removed support for more than eight mouse buttons.
  • +
  • [x86 CPUs] Improved Intel mobile CPU detection (e.g. disables RDTSC + timing on Centrino systems)
  • +
+ +

2.4.2

+
    +
  • Preliminary native Mac OS X support (via the Carbon interface)
  • +
  • Preliminary DOS support (DJGPP + Mesa)
  • +
  • Changed license to the zlib license (almost identical to the previous + GLFW license), so now GLFW is OSI Certified
  • +
  • Rewrote the GLFW documentation in LaTeX, meaning several improvements + (both visual and practical)
  • +
  • Added the support folder to the distribution, which includes + support for various languages
  • +
  • [Win32] Added OpenWatcom compiler support (thanks Sebastian + Schuberth!)
  • +
  • [Win32] Changed fallback timer from GetTickCount to timeGetTime, + which usually provides better resolution
  • +
  • [Win32] Bugfix: Accumulator buffer selection should be more + robust
  • +
  • [Win32] Bugfix: If stereo rendering is requested, and no stereo pixel + format could be created, glfwOpenWindow now fails
  • +
  • [Win32] Bugfix: glfwSetWindowSize now sets the size of the client + area, NOT the entire window, meaning that there is a 1:1 relationship + between glfwSetWindowSize and glfwGetWindowSize
  • +
  • [X11] Added FreeBSD and QNX support
  • +
  • [X11] Added support for non-pthread capable systems
  • +
  • [X11] Hopefully more robust configuration script (compile.sh)
  • +
  • [X11] Bugfix: When mouse cursor is hidden, mouse sensitivity is no + longer degraded
  • +
  • [X11] Bugfix: Source files EOL was PC style (CR/LF) in 2.4.1 (blame + my WinCVS configuration)
  • +
  • [X11] Bugfix: When a GLFW window is closed, input focus is properly + released
  • +
  • [X11] Bugfix: Iconification of fullscreen windows should now work + properly
  • +
  • [x86 CPUs] Improved RDTSC timing (e.g. RDTSC support on single-CPU + Intel Hyper-Threading enabled systems)
  • +
  • [AmigaOS] Added joystick support
  • +
  • [AmigaOS] Mouse cursor positioning is now implemented
  • +
  • [AmigaOS] Added support for Geek Gadgets GCC
  • +
  • [AmigaOS] Bugfix: glfwGetWindowParam now returns proper values for + all parameters (except for GLFW_ACCELERATED)
  • +
+ +

2.4.1

+
    +
  • Added AmigaOS support (preliminary)
  • +
  • GLFW for the X Window System now works under Mac OS X
  • +
  • [Win32] Bugfix: glfwWaitCond treated the timeout as milliseconds + instead of seconds
  • +
  • [X11] Bugfix: GLFW should now compile under IRIX v5.3
  • +
  • [X11] Bugfix: GLFW should now compile with Kylix
  • +
+ +

2.4

+
    +
  • Major source code rearrangement - much code is now shared between + different platforms, and it should be easier to port GLFW to new + platforms
  • +
  • Added a Unicode keyboard text input interface (CharCallback)
  • +
  • Keyboard key input is now slightly more internationalized: GLFW now + uses 8-bit ISO-8859-1 encoding for keys representing printable + characters (e.g. "Ö", "§", etc.), as + opposed to the previous 7-bit US-ASCII encoding
  • +
  • Added more key constants (F13-F25, keypad '=')
  • +
  • Added an enable/disable switch for automatic event polling from + glfwSwapBuffers
  • +
  • [X11] Added support for sysctl for querying the number of processors + in the system (if POSIX sysconf is not supported)
  • +
  • [X11] Bugfix: compile.sh now works with Sun sh (and hopefully others + too)
  • +
  • [X11] Bugfix: compile.sh now detects the need for -ldl when dlopen is + used
  • +
  • [Win32] Bugfix: When closing a fullscreen window under Win 9x/NT4, + the task bar icon now disappears properly
  • +
  • [Win32] Bugfix: GLFW should now compile on a wider range of MSVC + compilers (e.g. .NET) - Thanks Tim Little!
  • +
+ +

2.3.2

+
    +
  • Removed the silly limitation of 100 threads (the thread information + is now kept in a linked list)
  • +
  • General source cleanup (window state is now kept in a single + struct, plus some other minor changes)
  • +
  • [X11] Added Solaris gethrtime() support (not tested yet), which + should give an improved timer for Sun/Solaris stations
  • +
  • [X11] Some fixes to the 'compile.sh' script (-O for non-gcc compilers + and 'make x11-gcc' should now really force GCC)
  • +
+ +

2.3.1

+
    +
  • [X11] A minimalist configuration script was added that solves the + issue with glXGetProcAddressARB, and unifies all Unix/X11 Makefiles + into one template Makefile (well, one for GLFW, and one for the + examples)
  • +
+ +

2.3

+
    +
  • Added OpenGL stereo rendering support
  • +
  • Added a function for parsing the OpenGL version string + (glfwGetGLVersion)
  • +
  • [x86] Bugfix: Hopefully the CPU core clock dependent timer RDTSC will + never be used on CPUs with variable core frequencies anymore
  • +
  • [X11] Bugfix: GLFW could create stereo rendering capable windows, + even if it was not requested (GLFW 2.2.x did not support selection + of stereo rendering)
  • +
  • [X11] Bugfix: glfwGetProcAddress returned NULL on most systems (even + on those that supported glXGetProcAddressARB). Now GLFW assumes that + glXGetProcAddressARB is supported on all systems, which solves the + bug, but may result in compiler errors on some systems (please let me + know if you have any related problems).
  • +
+ +

2.2.3

+
    +
  • Bugfix: Checking for GL_SGIS_generate_mipmap is more robust
  • +
  • Bugfix: glfwLoadTexture2D will now fail if no window is opened
  • +
  • [Win32] Bugfix: Right shift was not detected under Win 9x/ME (it is + still not as good as under NT/2K/XP, but at least you get right + shifts)
  • +
  • [X11] Bugfix: Visuals are now selected more accurately. For instance, + glfwOpenWindow will no longer fail if you request a 24-bit color + buffer if only 16-bit color visuals are available (which means that + pong3d should work on 16-bit displays).
  • +
+ +

2.2.2

+
    +
  • [Win32] Bugfix: Windows did not always get focus (this was a tough + one!)
  • +
  • [Win32] Bugfix: glfwGetWindowParam did not work with + GLFW_ACCUM_*_BITS or GLFW_AUX_BUFFERS
  • +
  • [X11] Bugfix: Linux joystick Y axis positions were reversed
  • +
+ +

2.2.1

+
    +
  • [X11] Added joystick support for Linux
  • +
+ +

2.2

+
    +
  • Added joystick support (only supported under Windows so far)
  • +
  • Added joystick controls to pong3d.c (only 3 more lines of code)
  • +
  • Added glfwOpenWindowHint() function
  • +
  • It is now possible to specify a desired vertical monitor refresh + rate (for fullscreen windows)
  • +
  • It is now possible to request an accumulator buffer and auxiliary + buffers
  • +
  • Added glfwSetTime() function
  • +
  • Added a GLFW conversion of the MESA/GLUT gears.c demo to the example + programs
  • +
  • [Win32] gdi32.dll and winmm.dll are now loaded dynamically when + glfwInit() is called. This means that there is no need to link with + gdi32.lib or winmm.lib when using the static version of GLFW, which + should make GLFW usage more convenient.
  • +
  • [Win32] Bugfix: Greatly improved keyboard input (detect left/right + CTRL etc)
  • +
  • [Win32] Bugfix: glfwExtensionSupported now detects all WGL extensions + (e.g. WGL_ARB_pbuffer)
  • +
  • [Win32] Bugfix: Mouse cursor was not re-hidden when a GLFW window was + deselected and then selected again (with ALT+TAB)
  • +
  • [X11] Bugfix: Minor bug in the SGI timer - and ugly (unintended) SGI + timer debug info removed
  • +
  • [X11] Bugfix: glfwGetDesktopMode and glfwGetVideoModes no longer give + segmentation faults if no X server is available
  • +
+ +

2.1

+
    +
  • Added image and texture loading capabilities (support for the TGA + file format at the moment)
  • +
  • Added a new example program (mipmaps.c) for showing off the automatic + mipmap generation and texture loading capabilities of GLFW 2.1
  • +
  • Removed the separate TGA loader (tga.c in the examples directory) + since texture loading is supported natively by GLFW. Also updated the + Pong3D demo to use GLFW texture loading instead of tga.c.
  • +
  • Improved keyboard handling (e.g. numeric keypad keys can be + detected)
  • +
  • Added a new example program, keytest.c
  • +
  • Changed the GLFWvidmode structure and the corresponding API functions + to report pure color bits instead of the confusing (and unportable) + "BPP" field
  • +
  • Changed glfwSetWindowSize so that it operates in fullscreen mode + too
  • +
  • Added mouse wheel support under Windows (not Win95) and X11
  • +
  • Added window iconification functions (glfwInconifyWindow and + glfwRestoreWindow)
  • +
  • Improved iconification and deactivation handling under both Windows + and X11
  • +
  • Made it possible to turn on/off key repeat (the default is now no key + repeat)
  • +
  • Added SGI hardware timer support (CLOCK_SGI_CYCLE) for improved + timer resolution for SGI computers
  • +
  • Added support for the free Borland C++ Builder 5.x compiler for + Windows
  • +
  • Made it possible to compiler GLFW as a Windows DLL using any of the + supported compilers
  • +
  • Some constants have changed names (e.g. GLFW_REDBITS is now called + GLFW_RED_BITS)
  • +
  • Updated GLFW documentation (GLFW Users Guide and GLFW Reference + Manual) to reflect the changes in the API
  • +
  • [Win32] Bugfix: Corrected Cygwin toplevel makefile entry
  • +
  • [Win32] Bugfix: Fixed event lag bug
  • +
  • [Win32] Bugfix: Fixed Radeon 8500 crash
  • +
  • [X11] Bugfix: Fixed the window close bug
  • +
  • [X11] Bugfix: Iconification/deactivation is now detected
  • +
  • [X11] Bugfix: Non-OpenGL visuals are not listed anymore
  • +
  • [XFree86] Bugfix: Undesired video mode changes are now prevented
  • +
+ +

2.0.3

+
    +
  • Added precise CPU cycle based timing support (RDTSC) for x86 + CPUs (under both Windows and Unix)
  • +
  • Added a makefile option for building for Windows with Cygwin
  • +
  • Corrected the CC for Unix/X11 makefiles (-Wall is usually not a + supported flag for CC, so it was removed from the CFLAGS list)
  • +
+ +

2.0.2

+
    +
  • Added a makefile option for building for X11 with 'cc' rather than + 'gcc' (useful for IRIX users for instance).
  • +
  • [Win32] Bugfix: Mouse coordinates are now relative to the window + upper left corner, which also means that disabling the mouse cursor + in windowed mode should work much better.
  • +
  • [X11] Bugfix: Added a bunch of more keys that are recognized by + GLFW.
  • +
  • [X11] Bugfix: glfwGetNumberOfProcessors now works for IRIX (earlier + versions of GLFW would not compile under IRIX).
  • +
+ +

2.0.1

+
    +
  • glfwTerminate() will now be called automatically upon normal program + termination (using atexit())
  • +
  • [Win32] Bugfix: Buffer-swapping did not work if a window lost + focus.
  • +
  • [Win32] Bugfix: Top level Makefile did not work under Windows + 9x.
  • +
  • [Win32] Bugfix: NULL declaration in glfw.h was not MSVC 7.x + compatible.
  • +
  • [X11] Bugfix: GLFW would not build with C++ (e.g. g++).
  • +
+ +

2.0

+
    +
  • GLFW is no longer a single source file, but an entire link library.
  • +
  • Added multi threading support.
  • +
  • Added more window control.
  • +
  • New distribution layout (both Win32 and X11 version in same archive).
  • +
  • Added GLFW Users Manual and GLFW Reference Manual as PDF files.
  • +
  • Some bugfixes.
  • +
+ +

1.0.2

+
    +
  • Improved fullscreen functionality.
  • +
  • Added fullscreen support for X11.
  • +
+ +

1.0.1

+
    +
  • Added support for the X Window System.
  • +
  • Fixed bugs.
  • +
+ +

1.0.0

+
    +
  • First release.
  • +
  • Only supported Windows.
  • +
+ + + +

6. Directory structure of the GLFW distribution

+ +

Here is an overview of the directory structure of the GLFW distribution: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectoryContents
docsGLFW manuals in PDF format
examplesSeveral example programs in C
include/GLThe GLFW C/C++ header file
libThe source code for GLFW
lib/macosx + Mac OS X-specific code
lib/win32 + Windows-specific code
lib/x11Unix/X11-specific code
+ + +
+

7. Contacting the project

+ +

The official GLFW web site can be found here: http://glfw.sourceforge.net/. It +contains the latest version of GLFW, news and other information that is useful +for OpenGL development.

+ +

If you have questions related to the use of GLFW, we have a user's web +forum, and a user's mailing +list on SF.net, and the IRC channel #glfw on Freenode.

+ +

If you have a bug to report or a feature you'd like to request, please file +it in the SF.net +trackers.

+ +Finally, if you're interested in helping out with the development of GLFW or +porting it to your favorite platform, we have a developer's +mailing list, or you could join us on #glfw. + + + +

8. Acknowledgements

+ +

GLFW would not be what it is today without the help from: +

    + +
  • Marcus Geelnard, the original author and long-time maintainer of GLFW, + without whose brilliant work none of this would have happened.

  • + +
  • Robin Leffmann, for his work on Mac OS X and other platforms, and his + invaluable support.

  • + +
  • Keith Bauer, for his invaluable help with porting and maintaining GLFW on + Mac OS X, and for his many ideas.

  • + +
  • Ozzy @ Orkysquad, + for his dedication to GLFW, for debugging my source, and for his + valuable experience with game development.

  • + +
  • Jeff Molofee, the author of the excellent OpenGL tutorials at NeHe Productions. + Much of the Windows code of GLFW was originally based on Jeff's + code.

  • + +
  • Douglas C. Schmidt and Irfan Pyarali, for their excellent article Strategies for + Implementing POSIX Condition Variables on Win32, which was the basis for + the Win32 condition variable implementation in GLFW.

  • + +
  • Bobyshev Alexander and Martins Mozeiko, for the original proposal of + an FSAA hint and their work on the Win32 implementation of FSAA.

  • + +
  • Gerald Franz, who made GLFW compile under IRIX, and supplied patches + for the X11 keyboard translation routine.

  • + +
  • Bradley Smith, for his updates of the D support and his ports of the + remaining examples to the D language.

  • + +
  • Olivier Delannoy, for the initial implementation of FSAA support on + X11, cross-compiling support for MinGW and general extreme usefulness.
  • + +
  • Glenn Lewis, for helping out with support for the D programming + language.

  • + +
  • David Medlock, for doing the initial Lua port.

  • + +
  • Frank Wille, for helping me with the AmigaOS port and making GLFW + compile under IRIX 5.3.

  • + +
  • Matt Sealey, for helping me with the MorphOS port.

  • + +
  • Paul R. Deppe, who helped me with Cygwin support, and made an + adaption of PLIB + so that it can use GLFW (instead of GLUT).

  • + +
  • Jarrod Davis, for the Delphi port of GLFW.

  • + +
  • Toni Jovanoski, for helping me with the MASM32 port of GLFW, and + supplying the example program and fixed OpenGL and GLU bindings for + MASM32.

  • + +
  • Sebastian Schuberth, for the OpenWatcom makefiles.

  • + +
  • Dmitri Shuralyov, Samuli Tuomola, Santi Zupancic, Sylvain + Hellegouarch, and many others for support, bug reports and + testing.

  • + +
  • Дмитри Малышев, for the idea of a GLFW_NO_GLU macro.

  • + +
  • OpenGL.org, and all the people on + the discussion forums there that have provided help during the development of + GLFW.

  • + +
  • The MSDN Online Library, + which was used extensively for Windows development.

  • + +
  • All the feedback from the GLFW community - thank you!

  • + +
  • Everyone we forgot to thank - thank you!

  • +
+ + + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 00000000..2a915405 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,36 @@ + +link_libraries(libglfwStatic ${GLFW_LIBRARIES} ${OPENGL_glu_LIBRARY}) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include ${OPENGL_INCLUDE_DIR}) + +add_executable(defaults defaults.c) +add_executable(events events.c) +add_executable(joysticks joysticks.c) +add_executable(peter peter.c) +add_executable(reopen reopen.c) +add_executable(version version.c) + +if(APPLE) + # Set fancy names for bundles + add_executable(Accuracy MACOSX_BUNDLE accuracy.c) + add_executable(FSAA MACOSX_BUNDLE fsaa.c) + add_executable(Tearing MACOSX_BUNDLE tearing.c) +else() + # Set boring names for executables + add_executable(accuracy WIN32 accuracy.c) + add_executable(tearing WIN32 tearing.c) + add_executable(fsaa WIN32 fsaa.c) +endif(APPLE) + +if(MSVC) + # Tell MSVC to use main instead of WinMain for Windows subsystem executables + set_target_properties(accuracy defaults events fsaa peter reopen tearing version PROPERTIES LINK_FLAGS "/ENTRY:mainCRTStartup") +endif(MSVC) + +if(CYGWIN) + # Set cross-compile and subsystem compile and link flags + set_target_properties(accuracy defaults events fsaa joysticks peter reopen tearing version PROPERTIES COMPILE_FLAGS "-mno-cygwin") + set_target_properties(accuracy fsaa tearing PROPERTIES LINK_FLAGS "-mno-cygwin -mwindows") + set_target_properties(events defaults joysticks peter reopen version PROPERTIES LINK_FLAGS "-mno-cygwin -mconsole") +endif(CYGWIN) + diff --git a/tests/accuracy.c b/tests/accuracy.c new file mode 100644 index 00000000..3811cd81 --- /dev/null +++ b/tests/accuracy.c @@ -0,0 +1,103 @@ +//======================================================================== +// Mouse cursor accuracy test +// Copyright (c) Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// +// This test came about as the result of bug #1867804 +// +// No sign of said bug has so far been detected +// +//======================================================================== + +#include + +#include +#include + +static int cursor_x = 0, cursor_y = 0; +static int window_width = 640, window_height = 480; + +static void GLFWCALL window_size_callback(int width, int height) +{ + window_width = width; + window_height = height; + + glViewport(0, 0, window_width, window_height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(0.f, window_width, 0.f, window_height); +} + +static void GLFWCALL mouse_position_callback(int x, int y) +{ + cursor_x = x; + cursor_y = y; +} + +int main(void) +{ + if (!glfwInit()) + { + fprintf(stderr, "Failed to initialize GLFW\n"); + exit(EXIT_FAILURE); + } + + if (!glfwOpenWindow(window_width, window_height, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) + { + glfwTerminate(); + + fprintf(stderr, "Failed to open GLFW window\n"); + exit(EXIT_FAILURE); + } + + glfwSetWindowTitle("Cursor Inaccuracy Detector"); + glfwSetMousePosCallback(mouse_position_callback); + glfwSetWindowSizeCallback(window_size_callback); + glfwSwapInterval(1); + + glClearColor(0, 0, 0, 0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + while (glfwGetWindowParam(GLFW_OPENED)) + { + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(1.f, 1.f, 1.f); + + glBegin(GL_LINES); + glVertex2f(0.f, (GLfloat) window_height - cursor_y); + glVertex2f((GLfloat) window_width, (GLfloat) window_height - cursor_y); + glVertex2f((GLfloat) cursor_x, 0.f); + glVertex2f((GLfloat) cursor_x, (GLfloat) window_height); + glEnd(); + + glfwSwapBuffers(); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/tests/defaults.c b/tests/defaults.c new file mode 100644 index 00000000..58b77b4c --- /dev/null +++ b/tests/defaults.c @@ -0,0 +1,98 @@ +//======================================================================== +// Default window/context test +// Copyright (c) Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// +// This test creates a windowed mode window with all parameters set to +// default values and then reports the actual parameters of the created +// window and context +// +//======================================================================== + +#include + +#include +#include + +typedef struct +{ + int param; + char* name; +} Param; + +static Param parameters[] = +{ + { GLFW_ACCELERATED, "accelerated" }, + { GLFW_RED_BITS, "red bits" }, + { GLFW_GREEN_BITS, "green bits" }, + { GLFW_BLUE_BITS, "blue bits" }, + { GLFW_ALPHA_BITS, "alpha bits" }, + { GLFW_DEPTH_BITS, "depth bits" }, + { GLFW_STENCIL_BITS, "stencil bits" }, + { GLFW_REFRESH_RATE, "refresh rate" }, + { GLFW_ACCUM_RED_BITS, "accum red bits" }, + { GLFW_ACCUM_GREEN_BITS, "accum green bits" }, + { GLFW_ACCUM_BLUE_BITS, "accum blue bits" }, + { GLFW_ACCUM_ALPHA_BITS, "accum alpha bits" }, + { GLFW_AUX_BUFFERS, "aux buffers" }, + { GLFW_STEREO, "stereo" }, + { GLFW_FSAA_SAMPLES, "FSAA samples" }, + { GLFW_OPENGL_VERSION_MAJOR, "OpenGL major" }, + { GLFW_OPENGL_VERSION_MINOR, "OpenGL minor" }, + { GLFW_OPENGL_FORWARD_COMPAT, "OpenGL forward compatible" }, + { GLFW_OPENGL_DEBUG_CONTEXT, "OpenGL debug context" }, + { GLFW_OPENGL_PROFILE, "OpenGL profile" }, +}; + +int main(void) +{ + int i, width, height; + + if (!glfwInit()) + { + fprintf(stderr, "Failed to initialize GLFW\n"); + exit(1); + } + + if (!glfwOpenWindow(0, 0, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) + { + glfwTerminate(); + + fprintf(stderr, "Failed to open GLFW default window\n"); + exit(1); + } + + glfwGetWindowSize(&width, &height); + + printf("window size: %ix%i\n", width, height); + + for (i = 0; (size_t) i < sizeof(parameters) / sizeof(parameters[0]); i++) + { + printf("%s: %i\n", parameters[i].name, glfwGetWindowParam(parameters[i].param)); + } + + glfwCloseWindow(); + glfwTerminate(); + exit(0); +} + diff --git a/tests/events.c b/tests/events.c new file mode 100644 index 00000000..0434844e --- /dev/null +++ b/tests/events.c @@ -0,0 +1,309 @@ +//======================================================================== +// Event linter (event spewer) +// Copyright (c) Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// +// This test hooks every available callback and outputs their arguments +// +// Log messages go to stdout, error messages to stderr +// +// Every event also gets a (sequential) number to aid discussion of logs +// +//======================================================================== + +#include + +#include +#include +#include +#include + +static GLboolean keyrepeat = 0; +static GLboolean systemkeys = 1; +static unsigned int counter = 0; + +static const char* get_key_name(int key) +{ + switch (key) + { + case GLFW_KEY_UNKNOWN: return "unknown"; + case GLFW_KEY_SPACE: return "space"; + case GLFW_KEY_ESC: return "escape"; + case GLFW_KEY_F1: return "F1"; + case GLFW_KEY_F2: return "F2"; + case GLFW_KEY_F3: return "F3"; + case GLFW_KEY_F4: return "F4"; + case GLFW_KEY_F5: return "F5"; + case GLFW_KEY_F6: return "F6"; + case GLFW_KEY_F7: return "F7"; + case GLFW_KEY_F8: return "F8"; + case GLFW_KEY_F9: return "F9"; + case GLFW_KEY_F10: return "F10"; + case GLFW_KEY_F11: return "F11"; + case GLFW_KEY_F12: return "F12"; + case GLFW_KEY_F13: return "F13"; + case GLFW_KEY_F14: return "F14"; + case GLFW_KEY_F15: return "F15"; + case GLFW_KEY_F16: return "F16"; + case GLFW_KEY_F17: return "F17"; + case GLFW_KEY_F18: return "F18"; + case GLFW_KEY_F19: return "F19"; + case GLFW_KEY_F20: return "F20"; + case GLFW_KEY_F21: return "F21"; + case GLFW_KEY_F22: return "F22"; + case GLFW_KEY_F23: return "F23"; + case GLFW_KEY_F24: return "F24"; + case GLFW_KEY_F25: return "F25"; + case GLFW_KEY_UP: return "up"; + case GLFW_KEY_DOWN: return "down"; + case GLFW_KEY_LEFT: return "left"; + case GLFW_KEY_RIGHT: return "right"; + case GLFW_KEY_LSHIFT: return "left shift"; + case GLFW_KEY_RSHIFT: return "right shift"; + case GLFW_KEY_LCTRL: return "left control"; + case GLFW_KEY_RCTRL: return "right control"; + case GLFW_KEY_LALT: return "left alt"; + case GLFW_KEY_RALT: return "right alt"; + case GLFW_KEY_TAB: return "tab"; + case GLFW_KEY_ENTER: return "enter"; + case GLFW_KEY_BACKSPACE: return "backspace"; + case GLFW_KEY_INSERT: return "insert"; + case GLFW_KEY_DEL: return "delete"; + case GLFW_KEY_PAGEUP: return "page up"; + case GLFW_KEY_PAGEDOWN: return "page down"; + case GLFW_KEY_HOME: return "home"; + case GLFW_KEY_END: return "end"; + case GLFW_KEY_KP_0: return "keypad 0"; + case GLFW_KEY_KP_1: return "keypad 1"; + case GLFW_KEY_KP_2: return "keypad 2"; + case GLFW_KEY_KP_3: return "keypad 3"; + case GLFW_KEY_KP_4: return "keypad 4"; + case GLFW_KEY_KP_5: return "keypad 5"; + case GLFW_KEY_KP_6: return "keypad 6"; + case GLFW_KEY_KP_7: return "keypad 7"; + case GLFW_KEY_KP_8: return "keypad 8"; + case GLFW_KEY_KP_9: return "keypad 9"; + case GLFW_KEY_KP_DIVIDE: return "keypad divide"; + case GLFW_KEY_KP_MULTIPLY: return "keypad multiply"; + case GLFW_KEY_KP_SUBTRACT: return "keypad subtract"; + case GLFW_KEY_KP_ADD: return "keypad add"; + case GLFW_KEY_KP_DECIMAL: return "keypad decimal"; + case GLFW_KEY_KP_EQUAL: return "keypad equal"; + case GLFW_KEY_KP_ENTER: return "keypad enter"; + case GLFW_KEY_KP_NUM_LOCK: return "keypad num lock"; + case GLFW_KEY_CAPS_LOCK: return "caps lock"; + case GLFW_KEY_SCROLL_LOCK: return "scroll lock"; + case GLFW_KEY_PAUSE: return "pause"; + case GLFW_KEY_LSUPER: return "left super"; + case GLFW_KEY_RSUPER: return "right super"; + case GLFW_KEY_MENU: return "menu"; + } + + return NULL; +} + +static const char* get_action_name(int action) +{ + switch (action) + { + case GLFW_PRESS: + return "was pressed"; + case GLFW_RELEASE: + return "was released"; + } + + return "caused unknown action"; +} + +static const char* get_button_name(int button) +{ + switch (button) + { + case GLFW_MOUSE_BUTTON_LEFT: + return "left"; + case GLFW_MOUSE_BUTTON_RIGHT: + return "right"; + case GLFW_MOUSE_BUTTON_MIDDLE: + return "middle"; + } + + return NULL; +} + +static const char* get_character_string(int character) +{ + static char result[6 + 1]; + + int length = wctomb(result, character); + if (length == -1) + length = 0; + + result[length] = '\0'; + return result; +} + +static void GLFWCALL window_size_callback(int width, int height) +{ + printf("%08x at %0.3f: Window size: %i %i\n", + counter++, + glfwGetTime(), + width, + height); + + glViewport(0, 0, width, height); +} + +static int GLFWCALL window_close_callback(void) +{ + printf("%08x at %0.3f: Window close\n", counter++, glfwGetTime()); + return 1; +} + +static void GLFWCALL window_refresh_callback(void) +{ + printf("%08x at %0.3f: Window refresh\n", counter++, glfwGetTime()); +} + +static void GLFWCALL mouse_button_callback(int button, int action) +{ + const char* name = get_button_name(button); + + printf("%08x at %0.3f: Mouse button %i", counter++, glfwGetTime(), button); + + if (name) + printf(" (%s) was %s\n", name, get_action_name(action)); + else + printf(" was %s\n", get_action_name(action)); +} + +static void GLFWCALL mouse_position_callback(int x, int y) +{ + printf("%08x at %0.3f: Mouse position: %i %i\n", counter++, glfwGetTime(), x, y); +} + +static void GLFWCALL mouse_wheel_callback(int position) +{ + printf("%08x at %0.3f: Mouse wheel: %i\n", counter++, glfwGetTime(), position); +} + +static void GLFWCALL key_callback(int key, int action) +{ + const char* name = get_key_name(key); + + printf("%08x at %0.3f: Key 0x%04x", counter++, glfwGetTime(), key); + + if (name) + printf(" (%s) was %s\n", name, get_action_name(action)); + else if (isgraph(key)) + printf(" (%c) was %s\n", key, get_action_name(action)); + else + printf(" was %s\n", get_action_name(action)); + + if (action != GLFW_PRESS) + return; + + switch (key) + { + case 'R': + { + keyrepeat = !keyrepeat; + if (keyrepeat) + glfwEnable(GLFW_KEY_REPEAT); + else + glfwDisable(GLFW_KEY_REPEAT); + + printf("(( key repeat %s ))\n", keyrepeat ? "enabled" : "disabled"); + break; + } + + case 'S': + { + systemkeys = !systemkeys; + if( systemkeys ) + glfwEnable(GLFW_SYSTEM_KEYS); + else + glfwDisable(GLFW_SYSTEM_KEYS); + + printf("(( system keys %s ))\n", systemkeys ? "enabled" : "disabled"); + break; + } + } +} + +static void GLFWCALL char_callback(int character, int action) +{ + printf("%08x at %0.3f: Character 0x%04x", counter++, glfwGetTime(), character); + + printf(" (%s) %s\n", get_character_string(character), get_action_name(action)); +} + +int main(void) +{ + setlocale(LC_ALL, ""); + + if (!glfwInit()) + { + fprintf(stderr, "Failed to initialize GLFW\n"); + exit(1); + } + + printf("Library initialized\n"); + + if (!glfwOpenWindow(0, 0, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) + { + glfwTerminate(); + + fprintf(stderr, "Failed to create GLFW window"); + exit(1); + } + + printf("Window opened\n"); + + glfwSetWindowTitle("Event Linter"); + glfwSwapInterval(1); + + glfwSetWindowSizeCallback(window_size_callback); + glfwSetWindowCloseCallback(window_close_callback); + glfwSetWindowRefreshCallback(window_refresh_callback); + glfwSetMouseButtonCallback(mouse_button_callback); + glfwSetMousePosCallback(mouse_position_callback); + glfwSetMouseWheelCallback(mouse_wheel_callback); + glfwSetKeyCallback(key_callback); + glfwSetCharCallback(char_callback); + + printf("Key repeat should be %s\n", keyrepeat ? "enabled" : "disabled"); + printf("System keys should be %s\n", systemkeys ? "enabled" : "disabled"); + + printf("Main loop starting\n"); + + while (glfwGetWindowParam(GLFW_OPENED) == GL_TRUE) + { + glfwWaitEvents(); + glClear(GL_COLOR_BUFFER_BIT); + glfwSwapBuffers(); + } + + glfwTerminate(); + exit(0); +} + diff --git a/tests/fsaa.c b/tests/fsaa.c new file mode 100644 index 00000000..91c66d91 --- /dev/null +++ b/tests/fsaa.c @@ -0,0 +1,105 @@ +//======================================================================== +// Fullscreen multisampling anti-aliasing test +// Copyright (c) Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// +// This test renders two high contrast, slowly rotating quads, one aliased +// and one (hopefully) anti-aliased, thus allowing for visual verification +// of whether FSAA is indeed enabled +// +//======================================================================== + +#include + +#include +#include + +#ifndef GL_ARB_multisample +#define GL_MULTISAMPLE_ARB 0x809D +#endif + +static void GLFWCALL window_size_callback(int width, int height) +{ + glViewport(0, 0, width, height); +} + +int main(void) +{ + if (!glfwInit()) + { + fprintf(stderr, "Failed to initialize GLFW\n"); + exit(EXIT_FAILURE); + } + + glfwOpenWindowHint(GLFW_FSAA_SAMPLES, 4); + + if (!glfwOpenWindow(400, 400, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) + { + glfwTerminate(); + + fprintf(stderr, "Failed to open GLFW window\n"); + exit(EXIT_FAILURE); + } + + glfwSetWindowTitle("Aliasing Detector"); + glfwSetWindowSizeCallback(window_size_callback); + glfwSwapInterval(1); + + int samples = glfwGetWindowParam(GLFW_FSAA_SAMPLES); + if (samples) + printf("Context reports FSAA is supported with %i samples\n", samples); + else + printf("Context reports FSAA is unsupported\n"); + + glMatrixMode(GL_PROJECTION); + gluOrtho2D(0.f, 1.f, 0.f, 1.f); + + while (glfwGetWindowParam(GLFW_OPENED)) + { + GLfloat time = (GLfloat) glfwGetTime(); + + glClear(GL_COLOR_BUFFER_BIT); + + glLoadIdentity(); + glTranslatef(0.5f, 0.f, 0.f); + glRotatef(time, 0.f, 0.f, 1.f); + + glEnable(GL_MULTISAMPLE_ARB); + glColor3f(1.f, 1.f, 1.f); + glRectf(-0.25f, -0.25f, 0.25f, 0.25f); + + glLoadIdentity(); + glTranslatef(-0.5f, 0.f, 0.f); + glRotatef(time, 0.f, 0.f, 1.f); + + glDisable(GL_MULTISAMPLE_ARB); + glColor3f(1.f, 1.f, 1.f); + glRectf(-0.25f, -0.25f, 0.25f, 0.25f); + + glfwSwapBuffers(); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/tests/getopt.c b/tests/getopt.c new file mode 100644 index 00000000..b891b0a5 --- /dev/null +++ b/tests/getopt.c @@ -0,0 +1,253 @@ +/***************************************************************************** +* getopt.c - competent and free getopt library. +* $Header: /cvsroot/freegetopt/freegetopt/getopt.c,v 1.2 2003/10/26 03:10:20 vindaci Exp $ +* +* Copyright (c)2002-2003 Mark K. Kim +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* * Neither the original author of this software nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +* DAMAGE. +*/ +#include +#include +#include +#include "getopt.h" + + +/* 2009-10-12 Camilla Berglund + * + * Removed unused global static variable 'ID'. + */ + + +char* optarg = NULL; +int optind = 0; +int opterr = 1; +int optopt = '?'; + + +static char** prev_argv = NULL; /* Keep a copy of argv and argc to */ +static int prev_argc = 0; /* tell if getopt params change */ +static int argv_index = 0; /* Option we're checking */ +static int argv_index2 = 0; /* Option argument we're checking */ +static int opt_offset = 0; /* Index into compounded "-option" */ +static int dashdash = 0; /* True if "--" option reached */ +static int nonopt = 0; /* How many nonopts we've found */ + +static void increment_index() +{ + /* Move onto the next option */ + if(argv_index < argv_index2) + { + while(prev_argv[++argv_index] && prev_argv[argv_index][0] != '-' + && argv_index < argv_index2+1); + } + else argv_index++; + opt_offset = 1; +} + + +/* +* Permutes argv[] so that the argument currently being processed is moved +* to the end. +*/ +static int permute_argv_once() +{ + /* Movability check */ + if(argv_index + nonopt >= prev_argc) return 1; + /* Move the current option to the end, bring the others to front */ + else + { + char* tmp = prev_argv[argv_index]; + + /* Move the data */ + memmove(&prev_argv[argv_index], &prev_argv[argv_index+1], + sizeof(char**) * (prev_argc - argv_index - 1)); + prev_argv[prev_argc - 1] = tmp; + + nonopt++; + return 0; + } +} + + +int getopt(int argc, char** argv, char* optstr) +{ + int c = 0; + + /* If we have new argv, reinitialize */ + if(prev_argv != argv || prev_argc != argc) + { + /* Initialize variables */ + prev_argv = argv; + prev_argc = argc; + argv_index = 1; + argv_index2 = 1; + opt_offset = 1; + dashdash = 0; + nonopt = 0; + } + + /* Jump point in case we want to ignore the current argv_index */ + getopt_top: + + /* Misc. initializations */ + optarg = NULL; + + /* Dash-dash check */ + if(argv[argv_index] && !strcmp(argv[argv_index], "--")) + { + dashdash = 1; + increment_index(); + } + + /* If we're at the end of argv, that's it. */ + if(argv[argv_index] == NULL) + { + c = -1; + } + /* Are we looking at a string? Single dash is also a string */ + else if(dashdash || argv[argv_index][0] != '-' || !strcmp(argv[argv_index], "-")) + { + /* If we want a string... */ + if(optstr[0] == '-') + { + c = 1; + optarg = argv[argv_index]; + increment_index(); + } + /* If we really don't want it (we're in POSIX mode), we're done */ + else if(optstr[0] == '+' || getenv("POSIXLY_CORRECT")) + { + c = -1; + + /* Everything else is a non-opt argument */ + nonopt = argc - argv_index; + } + /* If we mildly don't want it, then move it back */ + else + { + if(!permute_argv_once()) goto getopt_top; + else c = -1; + } + } + /* Otherwise we're looking at an option */ + else + { + char* opt_ptr = NULL; + + /* Grab the option */ + c = argv[argv_index][opt_offset++]; + + /* Is the option in the optstr? */ + if(optstr[0] == '-') opt_ptr = strchr(optstr+1, c); + else opt_ptr = strchr(optstr, c); + /* Invalid argument */ + if(!opt_ptr) + { + if(opterr) + { + fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); + } + + optopt = c; + c = '?'; + + /* Move onto the next option */ + increment_index(); + } + /* Option takes argument */ + else if(opt_ptr[1] == ':') + { + /* ie, -oARGUMENT, -xxxoARGUMENT, etc. */ + if(argv[argv_index][opt_offset] != '\0') + { + optarg = &argv[argv_index][opt_offset]; + increment_index(); + } + /* ie, -o ARGUMENT (only if it's a required argument) */ + else if(opt_ptr[2] != ':') + { + /* One of those "you're not expected to understand this" moment */ + if(argv_index2 < argv_index) argv_index2 = argv_index; + while(argv[++argv_index2] && argv[argv_index2][0] == '-'); + optarg = argv[argv_index2]; + + /* Don't cross into the non-option argument list */ + if(argv_index2 + nonopt >= prev_argc) optarg = NULL; + + /* Move onto the next option */ + increment_index(); + } + else + { + /* Move onto the next option */ + increment_index(); + } + + /* In case we got no argument for an option with required argument */ + if(optarg == NULL && opt_ptr[2] != ':') + { + optopt = c; + c = '?'; + + if(opterr) + { + fprintf(stderr,"%s: option requires an argument -- %c\n", + argv[0], optopt); + } + } + } + /* Option does not take argument */ + else + { + /* Next argv_index */ + if(argv[argv_index][opt_offset] == '\0') + { + increment_index(); + } + } + } + + /* Calculate optind */ + if(c == -1) + { + optind = argc - nonopt; + } + else + { + optind = argv_index; + } + + return c; +} + + +/* vim:ts=3 +*/ diff --git a/tests/getopt.h b/tests/getopt.h new file mode 100644 index 00000000..0b78650a --- /dev/null +++ b/tests/getopt.h @@ -0,0 +1,63 @@ +/***************************************************************************** +* getopt.h - competent and free getopt library. +* $Header: /cvsroot/freegetopt/freegetopt/getopt.h,v 1.2 2003/10/26 03:10:20 vindaci Exp $ +* +* Copyright (c)2002-2003 Mark K. Kim +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* * Neither the original author of this software nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +* DAMAGE. +*/ +#ifndef GETOPT_H_ +#define GETOPT_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +extern char* optarg; +extern int optind; +extern int opterr; +extern int optopt; + +int getopt(int argc, char** argv, char* optstr); + + +#ifdef __cplusplus +} +#endif + + +#endif /* GETOPT_H_ */ + + +/* vim:ts=3 +*/ diff --git a/tests/iconify.c b/tests/iconify.c new file mode 100644 index 00000000..14c6e726 --- /dev/null +++ b/tests/iconify.c @@ -0,0 +1,158 @@ +//======================================================================== +// Iconify/restore test program +// Copyright (c) Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// +// This program is used to test the iconify/restore functionality for +// both fullscreen and windowed mode windows +// +//======================================================================== + +#include + +#include +#include + +#include "getopt.h" + +static void usage(void) +{ + printf("iconify [-h] [-f]\n"); +} + +static void GLFWCALL key_callback(int key, int action) +{ + printf("%0.2f Key %s\n", + glfwGetTime(), + action == GLFW_PRESS ? "pressed" : "released"); + + if (action != GLFW_PRESS) + return; + + switch (key) + { + case GLFW_KEY_SPACE: + glfwIconifyWindow(); + break; + case GLFW_KEY_ESC: + glfwCloseWindow(); + break; + } +} + +static void GLFWCALL size_callback(int width, int height) +{ + glViewport(0, 0, width, height); +} + +int main(int argc, char** argv) +{ + int width, height, ch; + int mode = GLFW_WINDOW; + GLboolean active = -1, iconified = -1; + + while ((ch = getopt(argc, argv, "fh")) != -1) + { + switch (ch) + { + case 'h': + usage(); + exit(EXIT_SUCCESS); + + case 'f': + mode = GLFW_FULLSCREEN; + break; + + default: + usage(); + exit(EXIT_FAILURE); + } + } + + if (!glfwInit()) + { + fprintf(stderr, "Failed to initialize GLFW\n"); + exit(EXIT_FAILURE); + } + + if (mode == GLFW_FULLSCREEN) + { + GLFWvidmode mode; + glfwGetDesktopMode(&mode); + width = mode.Width; + height = mode.Height; + } + else + { + width = 0; + height = 0; + } + + if (!glfwOpenWindow(width, height, 0, 0, 0, 0, 0, 0, mode)) + { + glfwTerminate(); + + fprintf(stderr, "Failed to open GLFW window\n"); + exit(EXIT_FAILURE); + } + + glfwSetWindowTitle("Iconify"); + glfwSwapInterval(1); + glfwSetKeyCallback(key_callback); + glfwSetWindowSizeCallback(size_callback); + + glEnable(GL_SCISSOR_TEST); + + while (glfwGetWindowParam(GLFW_OPENED)) + { + int width, height; + + if (iconified != glfwGetWindowParam(GLFW_ICONIFIED) || + active != glfwGetWindowParam(GLFW_ACTIVE)) + { + iconified = glfwGetWindowParam(GLFW_ICONIFIED); + active = glfwGetWindowParam(GLFW_ACTIVE); + + printf("%0.2f %s %s\n", + glfwGetTime(), + iconified ? "Iconified" : "Restored", + active ? "Active" : "Inactive"); + } + + glfwGetWindowSize(&width, &height); + + glScissor(0, 0, width, height); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + + glScissor(0, 0, 640, 480); + glClearColor(1, 1, 1, 0); + glClear(GL_COLOR_BUFFER_BIT); + + glfwSwapBuffers(); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/tests/joysticks.c b/tests/joysticks.c new file mode 100644 index 00000000..7015e131 --- /dev/null +++ b/tests/joysticks.c @@ -0,0 +1,136 @@ +/*======================================================================== + * This is a small test application for GLFW. + * joystick input test. + *========================================================================*/ + +#include + +#include +#include + +#define MAX_AXES 10 +#define MAX_BUTTONS 30 + +struct JoystickState +{ + int present; + int num_axes; + int num_buttons; + float axes[MAX_AXES]; + unsigned char buttons[MAX_BUTTONS]; +}; + +static struct JoystickState states[GLFW_JOYSTICK_LAST + 1]; + +int running; +int keyrepeat = 0; +int systemkeys = 1; + + +/*======================================================================== + * Retrieve joystick states + *========================================================================*/ +static void updateJoysticksState(void) +{ + int joy; + + for (joy = GLFW_JOYSTICK_1; joy < GLFW_JOYSTICK_LAST + 1; joy++) + { + printf("Updating information for joystick %d\n", joy); + states[joy].present = glfwGetJoystickParam(joy, GLFW_PRESENT); + if (states[joy].present == GL_TRUE) + { + states[joy].num_axes = glfwGetJoystickPos(joy, states[joy].axes, MAX_AXES); + states[joy].num_buttons = glfwGetJoystickButtons(joy, states[joy].buttons, MAX_BUTTONS); + } + } +} + +/*======================================================================== + * Print out the state of all joysticks on the standard output + *========================================================================*/ +static void displayJoysticksState(void) +{ + int joy; + int i; + + for (joy = GLFW_JOYSTICK_1; joy < GLFW_JOYSTICK_LAST + 1; joy++) + { + printf("Joystick %d: %s\n", joy, (states[joy].present == GL_TRUE ? "present" : "not connected")); + + if (states[joy].present == GL_TRUE) + { + if (states[joy].num_axes > 0) + { + printf(" axes: %.3f", states[joy].axes[0]); + for (i = 1; i < states[joy].num_axes; i++) + printf(", %.3f", states[joy].axes[i]); + + printf("\n"); + } + else + printf(" axes: none\n"); + + if (states[joy].num_buttons > 0) + { + printf(" buttons: 00 => %c", ((states[joy].buttons[0] == GLFW_PRESS) ? 'P' : 'R')); + + for (i = 1; i < states[joy].num_buttons; i++) + printf(", %02d => %c", i, ((states[joy].buttons[i] == GLFW_PRESS) ? 'P' : 'R')); + + printf("\n"); + } + else + printf(" buttons: none\n"); + } + } +} + +int main(void) +{ + double start; + double t; + double update; + + /* Initialise GLFW */ + glfwInit(); + printf("The program will work for 20 seconds and display every seconds the state of the joysticks\n"); + printf("Your computer is going to be very slow as the program is doing an active loop .....\n"); + + start = glfwGetTime(); + update = start; + + /* print the initial state of all joysticks */ + updateJoysticksState(); + printf("\n"); + displayJoysticksState(); + + running = GL_TRUE; + + /* Main loop */ + while (running) + { + /* Get time */ + t = glfwGetTime(); + + /* Display the state of all connected joysticks every secons */ + if ((t - update) > 1.0) + { + update = t; + printf("\n"); + updateJoysticksState(); + printf("\n"); + displayJoysticksState(); + } + + /* Check if the window was closed */ + if ((t - start) > 20.0) + running = GL_FALSE; + } + + /* Close OpenGL window and terminate GLFW */ + glfwTerminate(); + + return 0; +} + diff --git a/tests/peter.c b/tests/peter.c new file mode 100644 index 00000000..4d516614 --- /dev/null +++ b/tests/peter.c @@ -0,0 +1,137 @@ +//======================================================================== +// Mouse cursor bug test +// Copyright (c) Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// +// This test came about as the result of bugs #1262764, #1726540 and +// #1726592, all reported by the user peterpp, hence the name +// +// The utility of this test outside of these bugs is uncertain +// +//======================================================================== + +#include + +#include +#include + +static GLboolean cursor_enabled = GL_TRUE; + +static GLboolean open_window(void); + +static void toggle_mouse_cursor(void) +{ + if (cursor_enabled) + glfwDisable(GLFW_MOUSE_CURSOR); + else + glfwEnable(GLFW_MOUSE_CURSOR); + + cursor_enabled = !cursor_enabled; +} + +static void GLFWCALL mouse_position_callback(int x, int y) +{ + printf("Mouse moved to: %i %i\n", x, y); +} + +static void GLFWCALL key_callback(int key, int action) +{ + switch (key) + { + case GLFW_KEY_SPACE: + { + if (action == GLFW_PRESS) + toggle_mouse_cursor(); + + break; + } + + case 'R': + { + if (action == GLFW_PRESS) + { + glfwCloseWindow(); + open_window(); + } + + break; + } + } +} + +static void GLFWCALL window_size_callback(int width, int height) +{ + glViewport(0, 0, width, height); +} + +static GLboolean open_window(void) +{ + int x, y; + + if (!glfwOpenWindow(0, 0, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) + return GL_FALSE; + + glfwSetWindowTitle("Peter Detector"); + + glfwGetMousePos(&x, &y); + printf("Mouse position: %i %i\n", x, y); + + glfwDisable(GLFW_AUTO_POLL_EVENTS); + glfwSetWindowSizeCallback(window_size_callback); + glfwSetMousePosCallback(mouse_position_callback); + glfwSetKeyCallback(key_callback); + glfwSwapInterval(1); + + return GL_TRUE; +} + +int main(void) +{ + if (!glfwInit()) + { + fprintf(stderr, "Failed to initialize GLFW\n"); + exit(1); + } + + if (!open_window()) + { + glfwTerminate(); + + fprintf(stderr, "Failed to open GLFW window\n"); + exit(1); + } + + glClearColor(0.f, 0.f, 0.f, 0.f); + + while (glfwGetWindowParam(GLFW_OPENED)) + { + glClear(GL_COLOR_BUFFER_BIT); + + glfwSwapBuffers(); + glfwWaitEvents(); + } + + glfwTerminate(); + exit(0); +} + diff --git a/tests/reopen.c b/tests/reopen.c new file mode 100644 index 00000000..bfdda374 --- /dev/null +++ b/tests/reopen.c @@ -0,0 +1,170 @@ +//======================================================================== +// Window re-opener (open/close stress test) +// Copyright (c) Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// +// This test came about as the result of bug #1262773 +// +// It closes and re-opens the GLFW window every five seconds, alternating +// between windowed and fullscreen mode +// +// It also times and logs opening and closing actions and attempts to separate +// user initiated window closing from its own +// +//======================================================================== + +#include + +#include +#include + +static GLboolean closed = GL_FALSE; + +static const char* get_mode_name(int mode) +{ + switch (mode) + { + case GLFW_WINDOW: + return "windowed"; + case GLFW_FULLSCREEN: + return "fullscreen"; + default: + return "unknown"; + } +} + +static void GLFWCALL window_size_callback(int width, int height) +{ + glViewport(0, 0, width, height); +} + +static int GLFWCALL window_close_callback(void) +{ + printf("Close callback triggered\n"); + closed = GL_TRUE; + return 0; +} + +static void GLFWCALL key_callback(int key, int action) +{ + if (action != GLFW_PRESS) + return; + + switch (key) + { + case 'Q': + case GLFW_KEY_ESC: + closed = GL_TRUE; + break; + } +} + +static int open_window(int width, int height, int mode) +{ + double base = glfwGetTime(); + + if (!glfwOpenWindow(width, height, 0, 0, 0, 0, 16, 0, mode)) + { + fprintf(stderr, "Failed to create %s mode GLFW window\n", get_mode_name(mode)); + return 0; + } + + glfwSetWindowTitle("Window Re-opener"); + glfwSetWindowSizeCallback(window_size_callback); + glfwSetWindowCloseCallback(window_close_callback); + glfwSetKeyCallback(key_callback); + glfwSwapInterval(1); + + printf("Opening %s mode window took %0.3f seconds\n", + get_mode_name(mode), + glfwGetTime() - base); + + return 1; +} + +static void close_window(void) +{ + double base = glfwGetTime(); + + glfwCloseWindow(); + + printf("Closing window took %0.3f seconds\n", glfwGetTime() - base); +} + +int main(int argc, char** argv) +{ + int count = 0; + + if (!glfwInit()) + { + fprintf(stderr, "Failed to initialize GLFW\n"); + exit(1); + } + + for (;;) + { + if (!open_window(640, 480, (count & 1) ? GLFW_FULLSCREEN : GLFW_WINDOW)) + { + glfwTerminate(); + exit(1); + } + + glMatrixMode(GL_PROJECTION); + glOrtho(-1.f, 1.f, -1.f, 1.f, 1.f, -1.f); + glMatrixMode(GL_MODELVIEW); + + glClearColor(0.f, 0.f, 0.f, 0.f); + glColor3f(1.f, 1.f, 1.f); + + glfwSetTime(0.0); + + while (glfwGetTime() < 5.0) + { + glClear(GL_COLOR_BUFFER_BIT); + + glPushMatrix(); + glRotatef((GLfloat) glfwGetTime() * 100.f, 0.f, 0.f, 1.f); + glRectf(-0.5f, -0.5f, 1.f, 1.f); + glPopMatrix(); + + glfwSwapBuffers(); + + if (closed) + close_window(); + + if (!glfwGetWindowParam(GLFW_OPENED)) + { + printf("User closed window\n"); + + glfwTerminate(); + exit(0); + } + } + + printf("Closing window\n"); + close_window(); + + count++; + } +} + diff --git a/tests/tearing.c b/tests/tearing.c new file mode 100644 index 00000000..8e9f06a1 --- /dev/null +++ b/tests/tearing.c @@ -0,0 +1,84 @@ +//======================================================================== +// Vsync enabling test +// Copyright (c) Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// +// This test renders a high contrast, horizontally moving bar, allowing for +// visual verification of whether the set swap interval is indeed obeyed +// +//======================================================================== + +#include + +#include +#include +#include + +static void GLFWCALL window_size_callback(int width, int height) +{ + glViewport(0, 0, width, height); +} + +int main(void) +{ + float position; + + if (!glfwInit()) + { + fprintf(stderr, "Failed to initialize GLFW\n"); + exit(1); + } + + if (!glfwOpenWindow(0, 0, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) + { + glfwTerminate(); + + fprintf(stderr, "Failed to open GLFW window\n"); + exit(1); + } + + glfwSetWindowTitle("Tearing Detector"); + glfwSetWindowSizeCallback(window_size_callback); + glfwSwapInterval(1); + + glClearColor(0.f, 0.f, 0.f, 0.f); + glColor3f(1.f, 1.f, 1.f); + + glMatrixMode(GL_PROJECTION); + glOrtho(-1.f, 1.f, -1.f, 1.f, 1.f, -1.f); + glMatrixMode(GL_MODELVIEW); + + while (glfwGetWindowParam(GLFW_OPENED) == GL_TRUE) + { + glClear(GL_COLOR_BUFFER_BIT); + + position = cosf(glfwGetTime() * 4.f) * 0.75f; + glRectf(position - 0.25f, -1.f, position + 0.25f, 1.f); + + glfwSwapBuffers(); + } + + glfwTerminate(); + exit(0); +} + diff --git a/tests/version.c b/tests/version.c new file mode 100644 index 00000000..28f41b76 --- /dev/null +++ b/tests/version.c @@ -0,0 +1,253 @@ +//======================================================================== +// Version information dumper +// Copyright (c) Camilla Berglund +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// +// This test is a pale imitation of glxinfo(1), except not really +// +// It dumps GLFW and OpenGL version information +// +//======================================================================== + +#include + +#ifndef GL_VERSION_3_2 +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001 +#endif + +typedef const GLubyte * (APIENTRY *PFNGLGETSTRINGI) (GLenum, GLuint); + +#ifndef GL_VERSION_2_0 +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#endif + +#ifdef _MSC_VER +#define strcasecmp(x, y) _stricmp(x, y) +#endif + +#include +#include +#include + +#include "getopt.h" + +static void usage(void) +{ + printf("version [-h] [-m MAJOR] [-n MINOR] [-d] [-l] [-f] [-p PROFILE]\n"); + printf("available profiles: core compat\n"); +} + +static const char* get_profile_name(GLint mask) +{ + if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) + return "compatibility"; + if (mask & GL_CONTEXT_CORE_PROFILE_BIT) + return "core"; + + return "unknown"; +} + +static void list_extensions(int major, int minor) +{ + int i; + GLint count; + const GLubyte* extensions; + + printf("OpenGL context supported extensions:\n"); + + if (major > 2) + { + PFNGLGETSTRINGI glGetStringi = (PFNGLGETSTRINGI) glfwGetProcAddress("glGetStringi"); + if (!glGetStringi) + { + fprintf(stderr, "Failed to retrieve glGetStringi entry point"); + exit(EXIT_FAILURE); + } + + glGetIntegerv(GL_NUM_EXTENSIONS, &count); + + for (i = 0; i < count; i++) + puts((const char*) glGetStringi(GL_EXTENSIONS, i)); + } + else + { + extensions = glGetString(GL_EXTENSIONS); + while (*extensions != '\0') + { + if (*extensions == ' ') + putchar('\n'); + else + putchar(*extensions); + + extensions++; + } + } + + putchar('\n'); +} + +int main(int argc, char** argv) +{ + int ch, profile = 0, major = 1, minor = 1, revision; + GLboolean debug = GL_FALSE, forward = GL_FALSE, list = GL_FALSE; + GLint flags, mask; + + while ((ch = getopt(argc, argv, "dfhlm:n:p:")) != -1) + { + switch (ch) + { + case 'd': + debug = GL_TRUE; + break; + case 'f': + forward = GL_TRUE; + break; + case 'h': + usage(); + exit(0); + case 'l': + list = GL_TRUE; + break; + case 'm': + major = atoi(optarg); + break; + case 'n': + minor = atoi(optarg); + break; + case 'p': + if (strcasecmp(optarg, "core") == 0) + profile = GLFW_OPENGL_CORE_PROFILE; + else if (strcasecmp(optarg, "compat") == 0) + profile = GLFW_OPENGL_COMPAT_PROFILE; + else + { + usage(); + exit(EXIT_FAILURE); + } + break; + default: + usage(); + exit(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + + if (!glfwInit()) + { + fprintf(stderr, "Failed to initialize GLFW\n"); + exit(EXIT_FAILURE); + } + + if (major != 1 || minor != 1) + { + glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, major); + glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, minor); + } + + if (debug) + glfwOpenWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); + + if (forward) + glfwOpenWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + + if (profile != 0) + glfwOpenWindowHint(GLFW_OPENGL_PROFILE, profile); + + // We assume here that we stand a better chance of success by leaving all + // possible details of pixel format selection to GLFW + + if (!glfwOpenWindow(0, 0, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) + { + glfwTerminate(); + + fprintf(stderr, "Failed to open GLFW window\n"); + exit(EXIT_FAILURE); + } + + // Report GLFW version + + glfwGetVersion(&major, &minor, &revision); + + printf("GLFW header version: %u.%u.%u\n", + GLFW_VERSION_MAJOR, + GLFW_VERSION_MINOR, + GLFW_VERSION_REVISION); + + printf("GLFW library version: %u.%u.%u\n", major, minor, revision); + + if (major != GLFW_VERSION_MAJOR || + minor != GLFW_VERSION_MINOR || + revision != GLFW_VERSION_REVISION) + printf("*** WARNING: GLFW version mismatch! ***\n"); + + // Report OpenGL version + + printf("OpenGL context version string: \"%s\"\n", glGetString(GL_VERSION)); + + glfwGetGLVersion(&major, &minor, &revision); + + printf("OpenGL context version parsed by GLFW: %u.%u.%u\n", major, minor, revision); + + // Report OpenGL context properties + + if (major >= 3) + { + glGetIntegerv(GL_CONTEXT_FLAGS, &flags); + printf("OpenGL context flags:"); + + if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) + puts(" forward-compatible"); + else + puts(" none"); + } + + if (major > 3 || (major == 3 && minor >= 2)) + { + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask); + printf("OpenGL profile mask: 0x%08x (%s)\n", mask, get_profile_name(mask)); + } + + printf("OpenGL context renderer string: \"%s\"\n", glGetString(GL_RENDERER)); + printf("OpenGL context vendor string: \"%s\"\n", glGetString(GL_VENDOR)); + + if (major > 1) + { + printf("OpenGL context shading language version: \"%s\"\n", + glGetString(GL_SHADING_LANGUAGE_VERSION)); + } + + // Report OpenGL extensions + if (list) + list_extensions(major, minor); + + glfwTerminate(); + exit(EXIT_SUCCESS); +} +